diff --git a/Cargo.toml b/Cargo.toml index 7b569fe..746c704 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ raw-cpuid = { git = "https://github.com/gz/rust-cpuid", branch = "master" } redox_syscall = "0.1" [dependencies.goblin] -version = "0.0.8" +version = "0.0.10" default-features = false features = ["elf32", "elf64"] diff --git a/Xargo.toml b/Xargo.toml new file mode 100644 index 0000000..bc268c0 --- /dev/null +++ b/Xargo.toml @@ -0,0 +1,3 @@ +[dependencies.alloc] + +[dependencies.collections] diff --git a/linkers/x86_64.ld b/linkers/x86_64.ld index 546adaa..55640ec 100644 --- a/linkers/x86_64.ld +++ b/linkers/x86_64.ld @@ -29,6 +29,10 @@ SECTIONS { *(.data*) . = ALIGN(4096); __data_end = .; + __bss_start = .; + *(.bss*) + . = ALIGN(4096); + __bss_end = .; } .tdata : AT(ADDR(.tdata) - KERNEL_OFFSET) { @@ -43,13 +47,6 @@ SECTIONS { __tbss_end = .; } - .bss : AT(ADDR(.bss) - KERNEL_OFFSET) { - __bss_start = .; - *(.bss*) - . = ALIGN(4096); - __bss_end = .; - } - __end = .; /DISCARD/ : { diff --git a/src/acpi/aml/dataobj.rs b/src/acpi/aml/dataobj.rs new file mode 100644 index 0000000..4400c8d --- /dev/null +++ b/src/acpi/aml/dataobj.rs @@ -0,0 +1,168 @@ +use collections::vec::Vec; +use collections::string::String; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, get_namespace_string}; + +use super::type2opcode::{parse_def_buffer, parse_def_package, parse_def_var_package, + DefBuffer, DefPackage, DefVarPackage}; +use super::termlist::{parse_term_arg, TermArg}; +use super::namestring::{parse_super_name, SuperName}; + +#[derive(Debug, Clone)] +pub enum DataObj { + ComputationalData(ComputationalData), + DefPackage(DefPackage), + DefVarPackage(DefVarPackage) +} + +#[derive(Debug, Clone)] +pub enum DataRefObj { + DataObj(DataObj), + ObjectReference(TermArg), + DDBHandle(SuperName) +} + +#[derive(Debug, Clone)] +pub struct ArgObj(u8); +#[derive(Debug, Clone)] +pub struct LocalObj(u8); +// Not actually doing anything to contain data, but does give us type guarantees, which is useful + +#[derive(Debug, Clone)] +pub enum ComputationalData { + Byte(u8), + Word(u16), + DWord(u32), + QWord(u64), + String(String), + Zero, + One, + Ones, + DefBuffer(DefBuffer), + RevisionOp +} + +impl AmlExecutable for DataRefObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + DataRefObj::DataObj(ref cd) => cd.execute(namespace, scope), + _ => Some(AmlValue::Integer) + } + } +} + +impl AmlExecutable for DataObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + DataObj::ComputationalData(ref cd) => cd.execute(namespace, scope), + DataObj::DefPackage(ref pkg) => pkg.execute(namespace, scope), + _ => Some(AmlValue::Integer) + } + } +} + +impl AmlExecutable for ComputationalData { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + ComputationalData::Byte(b) => Some(AmlValue::IntegerConstant(b as u64)), + ComputationalData::Word(w) => Some(AmlValue::IntegerConstant(w as u64)), + ComputationalData::DWord(d) => Some(AmlValue::IntegerConstant(d as u64)), + ComputationalData::QWord(q) => Some(AmlValue::IntegerConstant(q as u64)), + ComputationalData::Zero => Some(AmlValue::IntegerConstant(0)), + ComputationalData::One => Some(AmlValue::IntegerConstant(1)), + ComputationalData::Ones => Some(AmlValue::IntegerConstant(0xFFFFFFFFFFFFFFFF)), + _ => Some(AmlValue::Integer) + } + } +} + +pub fn parse_data_obj(data: &[u8]) -> Result<(DataObj, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(DataObj::ComputationalData, parse_computational_data), + parser_wrap!(DataObj::DefPackage, parse_def_package), + parser_wrap!(DataObj::DefVarPackage, parse_def_var_package) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_data_ref_obj(data: &[u8]) -> Result<(DataRefObj, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(DataRefObj::DataObj, parse_data_obj), + parser_wrap!(DataRefObj::ObjectReference, parse_term_arg), + parser_wrap!(DataRefObj::DDBHandle, parse_super_name) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_arg_obj(data: &[u8]) -> Result<(ArgObj, usize), AmlInternalError> { + match data[0] { + 0x68 ... 0x6E => Ok((ArgObj(data[0] - 0x68), 1 as usize)), + _ => Err(AmlInternalError::AmlInvalidOpCode) + } +} + +pub fn parse_local_obj(data: &[u8]) -> Result<(LocalObj, usize), AmlInternalError> { + match data[0] { + 0x60 ... 0x67 => Ok((LocalObj(data[0] - 0x60), 1 as usize)), + _ => Err(AmlInternalError::AmlInvalidOpCode) + } +} + +fn parse_computational_data(data: &[u8]) -> Result<(ComputationalData, usize), AmlInternalError> { + match data[0] { + 0x0A => Ok((ComputationalData::Byte(data[1]), 2 as usize)), + 0x0B => { + let res = (data[1] as u16) + + ((data[2] as u16) << 8); + Ok((ComputationalData::Word(res), 3 as usize)) + }, + 0x0C => { + let res = (data[1] as u32) + + ((data[2] as u32) << 8) + + ((data[3] as u32) << 16) + + ((data[4] as u32) << 24); + Ok((ComputationalData::DWord(res), 5 as usize)) + }, + 0x0D => { + let mut cur_ptr: usize = 1; + let mut cur_string: Vec = vec!(); + + while data[cur_ptr] != 0x00 { + cur_string.push(data[cur_ptr]); + cur_ptr += 1; + } + + match String::from_utf8(cur_string) { + Ok(s) => Ok((ComputationalData::String(s.clone()), s.clone().len() + 2)), + Err(_) => Err(AmlInternalError::AmlParseError("String data - invalid string")) + } + }, + 0x0E => { + let res = (data[1] as u64) + + ((data[2] as u64) << 8) + + ((data[3] as u64) << 16) + + ((data[4] as u64) << 24) + + ((data[5] as u64) << 32) + + ((data[6] as u64) << 40) + + ((data[7] as u64) << 48) + + ((data[8] as u64) << 56); + Ok((ComputationalData::QWord(res), 9 as usize)) + }, + 0x00 => Ok((ComputationalData::Zero, 1 as usize)), + 0x01 => Ok((ComputationalData::One, 1 as usize)), + 0x5B => if data[1] == 0x30 { + Ok((ComputationalData::RevisionOp, 2 as usize)) + } else { + Err(AmlInternalError::AmlInvalidOpCode) + }, + 0xFF => Ok((ComputationalData::Ones, 1 as usize)), + _ => match parse_def_buffer(data) { + Ok((res, size)) => Ok((ComputationalData::DefBuffer(res), size)), + Err(e) => Err(e) + } + } +} diff --git a/src/acpi/aml/mod.rs b/src/acpi/aml/mod.rs new file mode 100644 index 0000000..296317d --- /dev/null +++ b/src/acpi/aml/mod.rs @@ -0,0 +1,85 @@ +//! # AML +//! Code to parse and execute AML tables + +use alloc::boxed::Box; +use collections::string::String; +use collections::vec::Vec; +use core::fmt::Debug; +use core::str::FromStr; + +use super::sdt::Sdt; + +#[macro_use] +mod parsermacros; + +mod namespace; +mod termlist; +mod namespacemodifier; +mod pkglength; +mod namestring; +mod namedobj; +mod dataobj; +mod type1opcode; +mod type2opcode; + +use self::termlist::{parse_term_list, TermObj}; +pub use self::namespace::{AmlNamespace, AmlValue}; +use self::namespace::AmlNamespaceContents; + +// TODO: This should be able to take parameters, and may also return multiple values +pub trait AmlExecutable { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option; +} + +// TODO: make private +pub enum AmlInternalError { + AmlParseError(&'static str), + AmlInvalidOpCode, + AmlDeferredLoad +} + +pub enum AmlError { + AmlParseError(&'static str) +} + +pub fn get_namespace_string(current: String, modifier: String) -> String { + if modifier.starts_with("\\") { + return modifier; + } + + if modifier.starts_with("^") { + // TODO + } + + let mut namespace = current.clone(); + namespace.push('.'); + namespace + &modifier +} + +pub fn parse_aml_table(sdt: &'static Sdt) -> Result { + let data = sdt.data(); + + let term_list = match parse_term_list(data) { + Ok(res) => res, + Err(AmlInternalError::AmlParseError(s)) => return Err(AmlError::AmlParseError(s)), + Err(AmlInternalError::AmlInvalidOpCode) => return Err(AmlError::AmlParseError("Unable to match opcode")), + Err(AmlInternalError::AmlDeferredLoad) => return Err(AmlError::AmlParseError("Deferred load reached top level")) + }; + + let global_namespace_specifier = String::from_str("\\").unwrap(); + // Unwrap is fine here. I mean come on, if this goes wrong you've got bigger problems than AML + // not loading... + + let mut global_namespace = AmlNamespace::new_namespace(&global_namespace_specifier); + term_list.execute(&mut global_namespace, global_namespace_specifier.clone()); + + Ok(global_namespace) +} + +pub fn is_aml_table(sdt: &'static Sdt) -> bool { + if &sdt.signature == b"DSDT" {//|| &sdt.signature == b"SSDT" { + true + } else { + false + } +} diff --git a/src/acpi/aml/namedobj.rs b/src/acpi/aml/namedobj.rs new file mode 100644 index 0000000..26cca7b --- /dev/null +++ b/src/acpi/aml/namedobj.rs @@ -0,0 +1,783 @@ +use alloc::boxed::Box; +use collections::string::String; +use collections::vec::Vec; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; +use super::namestring::{parse_name_string, parse_name_seg}; +use super::termlist::{parse_term_arg, parse_term_list, parse_object_list, TermArg, TermObj, Object}; +use super::pkglength::parse_pkg_length; +use super::type2opcode::{parse_def_buffer, DefBuffer}; + +#[derive(Debug, Clone)] +pub enum NamedObj { + DefBankField { + region_name: String, + bank_name: String, + bank_value: TermArg, + flags: FieldFlags, + field_list: Vec + }, + DefCreateBitField { + name: String, + source_buf: TermArg, + bit_index: TermArg + }, + DefCreateByteField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateWordField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateDWordField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateQWordField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateField { + name: String, + source_buf: TermArg, + bit_index: TermArg, + num_bits: TermArg + }, + DefDataRegion { + name: String, + signature: TermArg, + oem_id: TermArg, + oem_table_id: TermArg + }, + DefDevice { + name: String, + obj_list: Vec + }, + DefEvent { + name: String + }, + DefOpRegion { + name: String, + region: RegionSpace, + offset: TermArg, + len: TermArg + }, + DefField { + name: String, + flags: FieldFlags, + field_list: Vec + }, + DefIndexField { + idx_name: String, + data_name: String, + flags: FieldFlags, + field_list: Vec + }, + DefMethod { + name: String, + method: Method + }, + DefMutex { + name: String, + sync_level: u8 + }, + DefPowerRes { + name: String, + system_level: u8, + resource_order: u16, + obj_list: Vec + }, + DefProcessor { + name: String, + proc_id: u8, + p_blk_addr: u32, + p_blk_len: u8, + obj_list: Vec + }, + DefThermalZone { + name: String, + obj_list: Vec + }, + DeferredLoad(Vec) +} + +#[derive(Debug, Clone)] +pub struct Method { + arg_count: u8, + serialized: bool, + sync_level: u8, + term_list: Vec +} + +impl AmlExecutable for NamedObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + NamedObj::DefOpRegion { ref name, ref region, ref offset, ref len } => { + let local_scope_string = get_namespace_string(scope.clone(), name.clone()); + + let resolved_offset = match offset.execute(namespace, scope.clone()) { + Some(r) => r, + _ => return None + }; + + let resolved_len = match len.execute(namespace, scope.clone()) { + Some(r) => r, + _ => return None + }; + + namespace.push_to(local_scope_string, AmlNamespaceContents::OpRegion { + region: *region, + offset: resolved_offset, + len: resolved_len + }); + }, + NamedObj::DefField { ref name, ref flags, ref field_list } => { + let mut offset: usize = 0; + + for f in field_list { + match *f { + FieldElement::ReservedField { length } => offset += length, + FieldElement::NamedField { name: ref field_name, length } => { + let local_scope_string = get_namespace_string(scope.clone(), + field_name.clone()); + namespace.push_to(local_scope_string, AmlNamespaceContents::Field { + op_region: name.clone(), + flags: flags.clone(), + offset: offset.clone(), + length: length.clone() + }); + + offset += length; + }, + _ => () + } + } + }, + NamedObj::DefMethod { ref name, ref method } => { + let local_scope_string = get_namespace_string(scope.clone(), name.clone()); + namespace.push_to(local_scope_string, AmlNamespaceContents::Value( + AmlValue::Method(method.clone()))); + }, + _ => () + } + + None + } +} + +#[derive(Debug, Copy, Clone)] +pub enum RegionSpace { + SystemMemory, + SystemIO, + PCIConfig, + EmbeddedControl, + SMBus, + SystemCMOS, + PciBarTarget, + IPMI, + GeneralPurposeIO, + GenericSerialBus, + UserDefined(u8) +} + +#[derive(Debug, Clone)] +pub struct FieldFlags { + access_type: AccessType, + lock_rule: bool, + update_rule: UpdateRule +} + +#[derive(Debug, Clone)] +pub enum AccessType { + AnyAcc, + ByteAcc, + WordAcc, + DWordAcc, + QWordAcc, + BufferAcc +} + +#[derive(Debug, Clone)] +pub enum UpdateRule { + Preserve, + WriteAsOnes, + WriteAsZeros +} + +#[derive(Debug, Clone)] +pub enum FieldElement { + NamedField { + name: String, + length: usize + }, + ReservedField { + length: usize + }, + AccessField { + access_type: AccessType, + access_attrib: AccessAttrib + }, + ConnectFieldNameString(String), + ConnectFieldBufferData(DefBuffer), +} + +#[derive(Debug, Clone)] +pub enum AccessAttrib { + AttribBytes(u8), + AttribRawBytes(u8), + AttribRawProcessBytes(u8), + AttribQuick, + AttribSendReceive, + AttribByte, + AttribWord, + AttribBlock, + AttribProcessCall, + AttribBlockProcessCall +} + +pub fn parse_named_obj(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_selector! { + data, + parse_def_bank_field, + parse_def_create_bit_field, + parse_def_create_byte_field, + parse_def_create_word_field, + parse_def_create_dword_field, + parse_def_create_qword_field, + parse_def_create_field, + parse_def_data_region, + parse_def_event, + parse_def_device, + parse_def_op_region, + parse_def_field, + parse_def_index_field, + parse_def_method, + parse_def_mutex, + parse_def_power_res, + parse_def_processor, + parse_def_thermal_zone + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_def_bank_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x87); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (region_name, region_name_len) = match parse_name_string( + &data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(res) => res, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let (bank_name, bank_name_len) = match parse_name_string( + &data[2 + pkg_length_len + region_name_len .. 2 + pkg_length]) { + Ok(res) => res, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let (bank_value, bank_value_len) = match parse_term_arg( + &data[2 + pkg_length_len + region_name_len .. 2 + pkg_length]) { + Ok(res) => res, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let flags_raw = data[2 + pkg_length_len + region_name_len + bank_name_len + bank_value_len]; + let flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("BankField - invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlInternalError::AmlParseError("BankField - invalid update rule")) + } + }; + + let field_list = match parse_field_list( + &data[3 + pkg_length_len + region_name_len + bank_name_len + bank_value_len .. + 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefBankField {region_name, bank_name, bank_value, flags, field_list}, + 2 + pkg_length)) +} + +fn parse_def_create_bit_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8D); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (bit_index, bit_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + bit_index_len..])?; + + Ok((NamedObj::DefCreateBitField {name, source_buf, bit_index}, + 1 + source_buf_len + bit_index_len + name_len)) +} + +fn parse_def_create_byte_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8C); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateByteField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_word_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8B); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateWordField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_dword_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8A); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateDWordField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_qword_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8F); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateQWordField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x13); + + let (source_buf, source_buf_len) = parse_term_arg(&data[2..])?; + let (bit_index, bit_index_len) = parse_term_arg(&data[2 + source_buf_len..])?; + let (num_bits, num_bits_len) = parse_term_arg(&data[2 + source_buf_len + bit_index_len..])?; + let (name, name_len) = parse_name_string( + &data[2 + source_buf_len + bit_index_len + num_bits_len..])?; + + Ok((NamedObj::DefCreateField {name, source_buf, bit_index, num_bits}, + 2 + source_buf_len + bit_index_len + num_bits_len + name_len)) +} + +fn parse_def_data_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x88); + + let (name, name_len) = parse_name_string(&data[2..])?; + let (signature, signature_len) = parse_term_arg(&data[2 + name_len..])?; + let (oem_id, oem_id_len) = parse_term_arg(&data[2 + name_len + signature_len..])?; + let (oem_table_id, oem_table_id_len) = parse_term_arg( + &data[2 + name_len + signature_len + oem_id_len..])?; + + Ok((NamedObj::DefDataRegion {name, signature, oem_id, oem_table_id}, + 2 + name_len + signature_len + oem_id_len + oem_table_id_len)) +} + +fn parse_def_event(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x02); + + let (name, name_len) = parse_name_string(&data[2..])?; + + Ok((NamedObj::DefEvent {name}, 2 + name_len)) +} + +fn parse_def_device(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x82); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let obj_list = match parse_object_list(&data[2 + pkg_length_len + name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefDevice {name, obj_list}, 2 + pkg_length_len)) +} + +fn parse_def_op_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x80); + + let (name, name_len) = parse_name_string(&data[2..])?; + let region = match data[2 + name_len] { + 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, + 0x80 ... 0xFF => RegionSpace::UserDefined(data[2 + name_len]), + _ => return Err(AmlInternalError::AmlParseError("OpRegion - invalid region")) + }; + + let (offset, offset_len) = parse_term_arg(&data[3 + name_len..])?; + let (len, len_len) = parse_term_arg(&data[3 + name_len + offset_len..])?; + + Ok((NamedObj::DefOpRegion {name, region, offset, len}, 3 + name_len + offset_len + len_len)) +} + +fn parse_def_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x81); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let flags_raw = data[2 + pkg_length_len + name_len]; + let flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("Field - Invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlInternalError::AmlParseError("Field - Invalid update rule")) + } + }; + + let field_list = match parse_field_list(&data[3 + pkg_length_len + name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefField {name, flags, field_list}, 2 + pkg_length)) +} + +fn parse_def_index_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x86); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (idx_name, idx_name_len) = match parse_name_string( + &data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let (data_name, data_name_len) = match parse_name_string( + &data[2 + pkg_length_len + idx_name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let flags_raw = data[2 + pkg_length_len + idx_name_len + data_name_len]; + let flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("IndexField - Invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlInternalError::AmlParseError("IndexField - Invalid update rule")) + } + }; + + let field_list = match parse_field_list( + &data[3 + pkg_length_len + idx_name_len + data_name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefIndexField {idx_name, data_name, flags, field_list}, 2 + pkg_length)) +} + +fn parse_field_list(data: &[u8]) -> Result, AmlInternalError> { + let mut terms: Vec = vec!(); + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let (res, len) = match parse_field_element(&data[current_offset..]) { + Ok(r) => r, + Err(AmlInternalError::AmlInvalidOpCode) => + return Err(AmlInternalError::AmlParseError("FieldList - no valid field")), + Err(e) => return Err(e) + }; + + terms.push(res); + current_offset += len; + } + + Ok(terms) +} + +fn parse_field_element(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_selector! { + data, + parse_named_field, + parse_reserved_field, + parse_access_field, + parse_connect_field + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_named_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + let (name_seg, name_seg_len) = parse_name_seg(&data[0..4])?; + let name = match String::from_utf8(name_seg) { + Ok(s) => s, + Err(_) => return Err(AmlInternalError::AmlParseError("NamedField - invalid name")) + }; + let (length, length_len) = parse_pkg_length(&data[4..])?; + + Ok((FieldElement::NamedField {name, length}, 4 + length_len)) +} + +fn parse_reserved_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_opcode!(data, 0x00); + + let (length, length_len) = parse_pkg_length(&data[1..])?; + Ok((FieldElement::ReservedField {length}, 1 + length_len)) +} + +fn parse_access_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_opcode!(data, 0x01, 0x03); + + let flags_raw = data[1]; + let access_type = match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access type")) + }; + + let access_attrib = match (flags_raw & 0xC0) >> 6 { + 0 => match data[2] { + 0x02 => AccessAttrib::AttribQuick, + 0x04 => AccessAttrib::AttribSendReceive, + 0x06 => AccessAttrib::AttribByte, + 0x08 => AccessAttrib::AttribWord, + 0x0A => AccessAttrib::AttribBlock, + 0x0B => AccessAttrib::AttribBytes(data[3]), + 0x0C => AccessAttrib::AttribProcessCall, + 0x0D => AccessAttrib::AttribBlockProcessCall, + 0x0E => AccessAttrib::AttribRawBytes(data[3]), + 0x0F => AccessAttrib::AttribRawProcessBytes(data[3]), + _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access attrib")) + }, + 1 => AccessAttrib::AttribBytes(data[2]), + 2 => AccessAttrib::AttribRawBytes(data[2]), + 3 => AccessAttrib::AttribRawProcessBytes(data[2]), + _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access attrib")) + // This should never happen but the compiler bitches if I don't cover this + }; + + return Ok((FieldElement::AccessField {access_type, access_attrib}, if data[0] == 0x01 { + 3 as usize + } else { + 4 as usize + })) +} + +fn parse_connect_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_opcode!(data, 0x02); + + match parse_def_buffer(&data[1..]) { + Ok((buf, buf_len)) => return Ok((FieldElement::ConnectFieldBufferData(buf), buf_len + 1)), + Err(AmlInternalError::AmlInvalidOpCode) => (), + Err(e) => return Err(e) + } + + match parse_name_string(&data[1..]) { + Ok((name, name_len)) => Ok((FieldElement::ConnectFieldNameString(name), name_len + 1)), + Err(AmlInternalError::AmlInvalidOpCode) => Err(AmlInternalError::AmlParseError("ConnectField - unable to match field")), + Err(e) => Err(e) + } +} + +fn parse_def_method(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x14); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[1..])?; + let (name, name_len) = match parse_name_string(&data[1 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 1 + pkg_len].to_vec()), 1 + pkg_len)), + Err(e) => return Err(e) + }; + let flags = data[1 + pkg_len_len + name_len]; + + let arg_count = flags & 0x07; + let serialized = (flags & 0x08) == 0x08; + let sync_level = flags & 0xF0 >> 4; + + let term_list = match parse_term_list(&data[2 + pkg_len_len + name_len .. 1 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 1 + pkg_len].to_vec()), 1 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefMethod { + name: name, + method: Method { + arg_count, + serialized, + sync_level, + term_list + } + }, pkg_len + 1)) +} + +fn parse_def_mutex(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x01); + + let (name, name_len) = match parse_name_string(&data[2 ..]) { + Ok(p) => p, + Err(e) => return Err(e), + }; + let flags = data[2 + name_len]; + let sync_level = flags & 0x0F; + + Ok((NamedObj::DefMutex {name, sync_level}, name_len + 3)) +} + +fn parse_def_power_res(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x84); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + let system_level = data[2 + pkg_len_len + name_len]; + let resource_order: u16 = (data[3 + pkg_len_len + name_len] as u16) + + ((data[4 + pkg_len_len + name_len] as u16) << 8); + + let obj_list = match parse_object_list(&data[5 + pkg_len_len + name_len .. 2 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefPowerRes {name, system_level, resource_order, obj_list}, 2 + pkg_len)) +} + +fn parse_def_processor(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x83); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + let proc_id = data[2 + pkg_len_len + name_len]; + let p_blk_addr: u32 = (data[3 + pkg_len_len + name_len] as u32) + + ((data[4 + pkg_len_len + name_len] as u32) << 8) + + ((data[5 + pkg_len_len + name_len] as u32) << 16) + + ((data[6 + pkg_len_len + name_len] as u32) << 24); + let p_blk_len = data[7 + pkg_len_len + name_len]; + + let obj_list = match parse_object_list(&data[8 + pkg_len_len + name_len .. 2 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefProcessor {name, proc_id, p_blk_addr, p_blk_len, obj_list}, 2 + pkg_len)) +} + +fn parse_def_thermal_zone(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x85); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + let obj_list = match parse_object_list(&data[2 + pkg_len_len + name_len .. 2 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefThermalZone {name, obj_list}, 2 + pkg_len)) +} diff --git a/src/acpi/aml/namespace.rs b/src/acpi/aml/namespace.rs new file mode 100644 index 0000000..dc3c1c8 --- /dev/null +++ b/src/acpi/aml/namespace.rs @@ -0,0 +1,225 @@ +use alloc::boxed::Box; +use collections::string::String; +use collections::vec::Vec; + +use core::str::FromStr; + +use super::namedobj::{ RegionSpace, FieldFlags, Method }; + +#[derive(Debug, Clone)] +pub struct AmlNamespace { + name: String, + contents: AmlNamespaceContents +} + +#[derive(Debug, Clone)] +pub enum AmlNamespaceContents { + Value(AmlValue), + SubNamespace(Box), + Namespace(Vec), + OpRegion { + region: RegionSpace, + offset: AmlValue, + len: AmlValue + }, + Field { + op_region: String, + flags: FieldFlags, + offset: usize, + length: usize + } +} + +#[derive(Debug, Clone)] +pub enum AmlValue { + Uninitialized, + Buffer, + BufferField, + DDBHandle, + DebugObject, + Device, + Event, + FieldUnit, + Integer, + IntegerConstant(u64), + Method(Method), + Mutex, + ObjectReference, + OperationRegion, + Package(Vec), + String, + PowerResource, + Processor, + RawDataBuffer, + ThermalZone +} + +impl AmlValue { + pub fn get_as_package(&self) -> Option> { + match *self { + AmlValue::Package(ref p) => Some(p.clone()), + _ => None + } + } + + pub fn get_as_integer(&self) -> Option { + match *self { + AmlValue::IntegerConstant(ref i) => Some(i.clone()), + _ => None + } + } +} + +impl AmlNamespace { + pub fn new_namespace(name: &String) -> AmlNamespace { + AmlNamespace { + name: name.clone(), + contents: AmlNamespaceContents::Namespace(vec!()) + } + } + + pub fn find_str(&self, scope_str: &str) -> Option { + let scope_string = String::from_str(scope_str).unwrap(); + self.find(scope_string) + } + + pub fn find(&self, scope_string: String) -> Option { + if scope_string.len() == 0 { + match self.contents { + AmlNamespaceContents::Value(ref v) => return Some(v.clone()), + _ => return None + } + } + + let mut scope_string = scope_string.clone(); + + if scope_string.starts_with("\\") { + if self.name != "\\" { + return None; + } + + scope_string.remove(0); + } + + if scope_string.starts_with(".") { + scope_string.remove(0); + } + + if scope_string.len() == 0 { + match self.contents { + AmlNamespaceContents::Value(ref v) => return Some(v.clone()), + _ => return None + } + } + + let (current, nextset) = match scope_string.find(".") { + Some(s) => { + let (x, mut y) = scope_string.split_at(s); + y = &y[1..]; + + (String::from_str(x).unwrap(), String::from_str(y).unwrap()) + }, + None => if scope_string.len() <= 4 { + (scope_string, String::from_str("").unwrap()) + } else { + return None; + } + }; + + match self.contents { + AmlNamespaceContents::Namespace(ref namespace) => { + // TODO: Remove this while loop here, there has to be a more elegant way + let mut current_index = 0; + while current_index < namespace.len() { + match namespace[current_index] { + AmlNamespaceContents::SubNamespace(ref ns) => if ns.name == current { + return ns.find(nextset); + }, + _ => () + } + + current_index += 1; + } + }, + _ => () + } + + None + } + + pub fn push(&mut self, val: AmlNamespaceContents) { + match self.contents { + AmlNamespaceContents::Namespace(ref mut v) => v.push(val), + _ => () // TODO: Error this + } + } + + pub fn push_to(&mut self, scope_string: String, contents: AmlNamespaceContents) { + if scope_string.len() == 0 { + return; + } + + let mut scope_string = scope_string.clone(); + + if scope_string.starts_with("\\") { + if self.name != "\\" { + return; + // TODO: Error this + } + + scope_string.remove(0); + } + + if scope_string.starts_with(".") { + scope_string.remove(0); + } + + if scope_string.len() == 0 { + return; + } + + let (current, nextset) = match scope_string.find(".") { + Some(s) => { + let (x, mut y) = scope_string.split_at(s); + y = &y[1..]; + + (String::from_str(x).unwrap(), String::from_str(y).unwrap()) + }, + None => if scope_string.len() <= 4 { + (scope_string, String::from_str("").unwrap()) + } else { + return; + } + }; + + match self.contents { + AmlNamespaceContents::Namespace(ref mut namespace) => { + // TODO: Remove this while loop here, there has to be a more elegant way + let mut current_index = 0; + while current_index < namespace.len() { + match namespace[current_index] { + AmlNamespaceContents::SubNamespace(ref mut ns) => if ns.name == current { + ns.push_to(nextset, contents); + return; + }, + _ => () + } + + current_index += 1; + } + + let mut next = AmlNamespace { + name: current, + contents: contents + }; + + namespace.push(AmlNamespaceContents::SubNamespace(Box::new(next))); + } + _ => () // TODO: Error this + } + } + + pub fn push_subordinate_namespace(&mut self, scope_string: String) { + self.push_to(scope_string, AmlNamespaceContents::Namespace(vec!())); + } +} diff --git a/src/acpi/aml/namespacemodifier.rs b/src/acpi/aml/namespacemodifier.rs new file mode 100644 index 0000000..217347a --- /dev/null +++ b/src/acpi/aml/namespacemodifier.rs @@ -0,0 +1,102 @@ +use alloc::boxed::Box; +use collections::string::String; +use collections::vec::Vec; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; +use super::pkglength::parse_pkg_length; +use super::namestring::parse_name_string; +use super::termlist::{parse_term_list, TermObj}; +use super::dataobj::{parse_data_ref_obj, DataRefObj}; + +#[derive(Debug, Clone)] +pub enum NamespaceModifier { + Name { + name: String, + data_ref_obj: DataRefObj + }, + Scope { + name: String, + terms: Vec + }, + Alias { + source_name: String, + alias_name: String + }, + DeferredLoad(Vec) +} + +impl AmlExecutable for NamespaceModifier { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + NamespaceModifier::Scope { name: ref name, terms: ref terms } => { + let local_scope_string = get_namespace_string(scope, name.clone()); + namespace.push_subordinate_namespace(local_scope_string.clone()); + + terms.execute(namespace, local_scope_string); + }, + NamespaceModifier::Name { ref name, ref data_ref_obj } => { + let local_scope_string = get_namespace_string(scope.clone(), name.clone()); + let dro = match data_ref_obj.execute(namespace, scope) { + Some(s) => s, + None => return None + }; + + namespace.push_to(local_scope_string, AmlNamespaceContents::Value(dro)); + }, + _ => () + } + + None + } +} + +pub fn parse_namespace_modifier(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_selector! { + data, + parse_alias_op, + parse_scope_op, + parse_name_op + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_alias_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_opcode!(data, 0x06); + + let (source_name, source_name_len) = parse_name_string(&data[1..])?; + let (alias_name, alias_name_len) = parse_name_string(&data[1 + source_name_len..])?; + + Ok((NamespaceModifier::Alias {source_name, alias_name}, 1 + source_name_len + alias_name_len)) +} + +fn parse_name_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_opcode!(data, 0x08); + + let (name, name_len) = parse_name_string(&data[1..])?; + let (data_ref_obj, data_ref_obj_len) = parse_data_ref_obj(&data[1 + name_len..])?; + + Ok((NamespaceModifier::Name {name, data_ref_obj}, 1 + name_len + data_ref_obj_len)) +} + +fn parse_scope_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_opcode!(data, 0x10); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (name, name_len) = match parse_name_string(&data[1 + pkg_length_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamespaceModifier::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + 1 + pkg_length)), + Err(e) => return Err(e) + }; + let terms = match parse_term_list(&data[1 + pkg_length_len + name_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamespaceModifier::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamespaceModifier::Scope {name, terms}, pkg_length + 1)) +} diff --git a/src/acpi/aml/namestring.rs b/src/acpi/aml/namestring.rs new file mode 100644 index 0000000..8015a8c --- /dev/null +++ b/src/acpi/aml/namestring.rs @@ -0,0 +1,188 @@ +use collections::vec::Vec; +use collections::string::String; + +use super::AmlInternalError; + +use super::dataobj::{parse_arg_obj, parse_local_obj, ArgObj, LocalObj}; +use super::type2opcode::{parse_type6_opcode, Type6OpCode}; + +#[derive(Debug, Clone)] +pub enum SuperName { + NameString(String), + ArgObj(ArgObj), + LocalObj(LocalObj), + DebugObj, + Type6OpCode(Type6OpCode) +} + +#[derive(Debug, Clone)] +pub enum Target { + SuperName(SuperName), + Null +} + +pub fn parse_name_string(data: &[u8]) -> Result<(String, usize), AmlInternalError> { + let mut characters: Vec = vec!(); + let mut starting_index: usize = 0; + + if data[0] == 0x5C { + characters.push(data[0]); + starting_index = 1; + } else if data[0] == 0x5E { + while data[starting_index] == 0x5E { + characters.push(data[starting_index]); + starting_index += 1; + } + } + + let sel = |data| { + parser_selector! { + data, + parse_dual_name_path, + parse_multi_name_path, + parse_null_name, + parse_name_seg + }; + + Err(AmlInternalError::AmlInvalidOpCode) + }; + let (mut chr, len) = sel(&data[starting_index..])?; + characters.append(&mut chr); + + let name_string = String::from_utf8(characters); + + match name_string { + Ok(s) => Ok((s.clone(), len + starting_index)), + Err(_) => Err(AmlInternalError::AmlParseError("Namestring - Name is invalid")) + } +} + +fn parse_null_name(data: &[u8]) -> Result<(Vec, usize), AmlInternalError> { + parser_opcode!(data, 0x00); + Ok((vec!(), 1 as usize)) +} + +pub fn parse_name_seg(data: &[u8]) -> Result<(Vec, usize), AmlInternalError> { + match data[0] { + 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + match data[1] { + 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + match data[2] { + 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + match data[3] { + 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + let mut name_seg = vec!(data[0], data[1], data[2], data[3]); + while *(name_seg.last().unwrap()) == 0x5F { + name_seg.pop(); + } + + Ok((name_seg, 4 as usize)) +} + +fn parse_dual_name_path(data: &[u8]) -> Result<(Vec, usize), AmlInternalError> { + parser_opcode!(data, 0x2E); + + let mut characters: Vec = vec!(); + let mut dual_len: usize = 1; + + match parse_name_seg(&data[1..5]) { + Ok((mut v, len)) => { + characters.append(&mut v); + dual_len += len; + }, + Err(e) => return Err(e) + } + + characters.push(0x2E); + + match parse_name_seg(&data[5..9]) { + Ok((mut v, len)) => { + characters.append(&mut v); + dual_len += len; + }, + Err(e) => return Err(e) + } + + Ok((characters, dual_len)) +} + +fn parse_multi_name_path(data: &[u8]) -> Result<(Vec, usize), AmlInternalError> { + parser_opcode!(data, 0x2F); + + let seg_count = data[1]; + if seg_count == 0x00 { + return Err(AmlInternalError::AmlParseError("MultiName Path - can't have zero name segments")); + } + + let mut current_seg = 0; + let mut characters: Vec = vec!(); + let mut multi_len: usize = 2; + + while current_seg < seg_count { + match parse_name_seg(&data[(current_seg as usize * 4) + 2 ..]) { + Ok((mut v, len)) => { + characters.append(&mut v); + multi_len += len; + }, + Err(e) => return Err(e) + } + + characters.push(0x2E); + + current_seg += 1; + } + + characters.pop(); + + Ok((characters, multi_len)) +} + +pub fn parse_super_name(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_selector! { + data, + parse_simple_name, + parser_wrap!(SuperName::Type6OpCode, parse_type6_opcode), + parse_debug_obj + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_debug_obj(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x31); + Ok((SuperName::DebugObj, 2 as usize)) +} + +pub fn parse_simple_name(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(SuperName::NameString, parse_name_string), + parser_wrap!(SuperName::ArgObj, parse_arg_obj), + parser_wrap!(SuperName::LocalObj, parse_local_obj) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_target(data: &[u8]) -> Result<(Target, usize), AmlInternalError> { + if data[0] == 0x00 { + Ok((Target::Null, 1 as usize)) + } else { + match parse_super_name(data) { + Ok((name, name_len)) => Ok((Target::SuperName(name), name_len)), + Err(e) => Err(e) + } + } +} diff --git a/src/acpi/aml/parsermacros.rs b/src/acpi/aml/parsermacros.rs new file mode 100644 index 0000000..50e3aed --- /dev/null +++ b/src/acpi/aml/parsermacros.rs @@ -0,0 +1,49 @@ +#[macro_export] +macro_rules! parser_selector { + {$data:expr, $func:expr} => { + match $func($data) { + Ok(res) => return Ok(res), + Err(AmlInternalError::AmlInvalidOpCode) => (), + Err(e) => return Err(e) + } + }; + {$data:expr, $func:expr, $($funcs:expr),+} => { + parser_selector! {$data, $func}; + parser_selector! {$data, $($funcs),*}; + }; +} + +#[macro_export] +macro_rules! parser_wrap { + ($wrap:expr, $func:expr) => { + |data| { + match $func(data) { + Ok((res, size)) => Ok(($wrap(res), size)), + Err(e) => Err(e) + } + } + }; +} + +#[macro_export] +macro_rules! parser_opcode { + ($data:expr, $opcode:expr) => { + if $data[0] != $opcode { + return Err(AmlInternalError::AmlInvalidOpCode); + } + }; + ($data:expr, $opcode:expr, $alternate_opcode:expr) => { + if $data[0] != $opcode && $data[0] != $alternate_opcode { + return Err(AmlInternalError::AmlInvalidOpCode); + } + }; +} + +#[macro_export] +macro_rules! parser_opcode_extended { + ($data:expr, $opcode:expr) => { + if $data[0] != 0x5B || $data[1] != $opcode { + return Err(AmlInternalError::AmlInvalidOpCode); + } + }; +} diff --git a/src/acpi/aml/pkglength.rs b/src/acpi/aml/pkglength.rs new file mode 100644 index 0000000..7c4ace8 --- /dev/null +++ b/src/acpi/aml/pkglength.rs @@ -0,0 +1,25 @@ +use super::AmlInternalError; + +pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlInternalError> { + let lead_byte = data[0]; + let count_bytes: usize = (lead_byte >> 6) as usize; + + if count_bytes == 0 { + return Ok(((lead_byte & 0x3F) as usize, 1 as usize)); + } + + let upper_two = (lead_byte >> 4) & 0x03; + if upper_two != 0 { + return Err(AmlInternalError::AmlParseError("Invalid package length")); + } + + let mut current_byte = 0; + let mut pkg_len: usize = (lead_byte & 0x0F) as usize; + + while current_byte < count_bytes { + pkg_len += (data[1 + current_byte] as u32 * 16 * (256 as u32).pow(current_byte as u32)) as usize; + current_byte += 1; + } + + return Ok((pkg_len, count_bytes + 1)); +} diff --git a/src/acpi/aml/termlist.rs b/src/acpi/aml/termlist.rs new file mode 100644 index 0000000..b236584 --- /dev/null +++ b/src/acpi/aml/termlist.rs @@ -0,0 +1,135 @@ +use alloc::boxed::Box; +use collections::string::String; +use collections::vec::Vec; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, get_namespace_string}; +use super::namespacemodifier::{parse_namespace_modifier, NamespaceModifier}; +use super::namedobj::{parse_named_obj, NamedObj}; +use super::dataobj::{parse_data_obj, parse_arg_obj, parse_local_obj, DataObj, ArgObj, LocalObj}; +use super::type1opcode::{parse_type1_opcode, Type1OpCode}; +use super::type2opcode::{parse_type2_opcode, Type2OpCode}; +use super::namestring::parse_name_string; + +#[derive(Debug, Clone)] +pub enum TermArg { + LocalObj(Box), + DataObj(Box), + ArgObj(Box), + Type2Opcode(Box) +} + +#[derive(Debug, Clone)] +pub enum TermObj { + NamespaceModifier(Box), + NamedObj(Box), + Type1Opcode(Box), + Type2Opcode(Box) +} + +#[derive(Debug, Clone)] +pub enum Object { + NamespaceModifier(Box), + NamedObj(Box) +} + +#[derive(Debug, Clone)] +pub struct MethodInvocation { + +} + +impl AmlExecutable for Vec { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + for term in self { + term.execute(namespace, scope.clone()); + } + + None + } +} + +impl AmlExecutable for TermArg { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + TermArg::LocalObj(ref l) => Some(AmlValue::Integer), + TermArg::DataObj(ref d) => d.execute(namespace, scope), + TermArg::ArgObj(ref a) => Some(AmlValue::Integer), + TermArg::Type2Opcode(ref o) => Some(AmlValue::Integer) + } + } +} + +impl AmlExecutable for TermObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + TermObj::NamespaceModifier(ref res) => res.execute(namespace, scope.clone()), + TermObj::NamedObj(ref res) => res.execute(namespace, scope.clone()), + TermObj::Type1Opcode(ref res) => res.execute(namespace, scope.clone()), + TermObj::Type2Opcode(ref res) => res.execute(namespace, scope.clone()) + } + } +} + +pub fn parse_term_list(data: &[u8]) -> Result, AmlInternalError> { + let mut terms: Vec = vec!(); + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let (res, len) = parse_term_obj(&data[current_offset..])?; + terms.push(res); + current_offset += len; + } + + Ok(terms) +} + +pub fn parse_term_arg(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(TermArg::LocalObj, parser_wrap!(Box::new, parse_local_obj)), + parser_wrap!(TermArg::DataObj, parser_wrap!(Box::new, parse_data_obj)), + parser_wrap!(TermArg::ArgObj, parser_wrap!(Box::new, parse_arg_obj)), + parser_wrap!(TermArg::Type2Opcode, parser_wrap!(Box::new, parse_type2_opcode)) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_object_list(data: &[u8]) -> Result, AmlInternalError> { + let mut terms: Vec = vec!(); + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let (res, len) = parse_object(&data[current_offset..])?; + terms.push(res); + current_offset += len; + } + + Ok(terms) +} + +fn parse_object(data: &[u8]) -> Result<(Object, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(Object::NamespaceModifier, parser_wrap!(Box::new, parse_namespace_modifier)), + parser_wrap!(Object::NamedObj, parser_wrap!(Box::new, parse_named_obj)) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_method_invocation(data: &[u8]) -> Result<(MethodInvocation, usize), AmlInternalError> { + let (name, name_len) = parse_name_string(data)?; + Err(AmlInternalError::AmlDeferredLoad) +} + +fn parse_term_obj(data: &[u8]) -> Result<(TermObj, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(TermObj::NamespaceModifier, parser_wrap!(Box::new, parse_namespace_modifier)), + parser_wrap!(TermObj::NamedObj, parser_wrap!(Box::new, parse_named_obj)), + parser_wrap!(TermObj::Type1Opcode, parser_wrap!(Box::new, parse_type1_opcode)), + parser_wrap!(TermObj::Type2Opcode, parser_wrap!(Box::new, parse_type2_opcode)) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} diff --git a/src/acpi/aml/type1opcode.rs b/src/acpi/aml/type1opcode.rs new file mode 100644 index 0000000..103e542 --- /dev/null +++ b/src/acpi/aml/type1opcode.rs @@ -0,0 +1,259 @@ +use alloc::boxed::Box; +use collections::string::String; +use collections::vec::Vec; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; +use super::pkglength::parse_pkg_length; +use super::termlist::{parse_term_arg, parse_term_list, TermObj, TermArg}; +use super::namestring::{parse_name_string, parse_super_name, SuperName}; + +#[derive(Debug, Clone)] +pub enum Type1OpCode { + DefBreak, + DefBreakPoint, + DefContinue, + DefFatal { + fatal_type: u8, + fatal_code: u16, + fatal_arg: TermArg + }, + DefNoop, + DefIfElse { + if_block: IfBlock, + else_block: IfBlock + }, + DefLoad { + name: String, + ddb_handle_object: SuperName + }, + DefNotify { + object: SuperName, + value: TermArg + }, + DefRelease(SuperName), + DefReset(SuperName), + DefSignal(SuperName), + DefSleep(TermArg), + DefStall(TermArg), + DefUnload(SuperName), + DefWhile { + predicate: TermArg, + block: Vec + }, + DefReturn(TermArg), + DeferredLoad(Vec) +} + +impl AmlExecutable for Type1OpCode { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + None + } +} + +#[derive(Debug, Clone)] +pub enum IfBlock { + If { + predicate: TermArg, + if_block: Vec + }, + Else(Vec), + NoBlock, + DeferredLoad(Vec) +} + +pub fn parse_type1_opcode(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + match data[0] { + 0xA5 => return Ok((Type1OpCode::DefBreak, 1 as usize)), + 0xCC => return Ok((Type1OpCode::DefBreakPoint, 1 as usize)), + 0x9F => return Ok((Type1OpCode::DefContinue, 1 as usize)), + 0xA3 => return Ok((Type1OpCode::DefNoop, 1 as usize)), + _ => () + } + + parser_selector! { + data, + parse_def_fatal, + parse_def_if_else, + parse_def_load, + parse_def_notify, + parse_def_release, + parse_def_reset, + parse_def_signal, + parse_def_sleep, + parse_def_stall, + parse_def_return, + parse_def_unload, + parse_def_while + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_def_fatal(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x32 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let fatal_type = data[2]; + let fatal_code: u16 = (data[3] as u16) + + ((data[4] as u16) << 8); + let (fatal_arg, fatal_arg_len) = parse_term_arg(&data[5..])?; + + Ok((Type1OpCode::DefFatal {fatal_type, fatal_code, fatal_arg}, fatal_arg_len + 5)) +} + +fn parse_def_load(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x20 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (name, name_len) = parse_name_string(&data[2..])?; + let (ddb_handle_object, ddb_handle_object_len) = parse_super_name(&data[2 + name_len..])?; + + Ok((Type1OpCode::DefLoad {name, ddb_handle_object}, 2 + name_len + ddb_handle_object_len)) +} + +fn parse_def_notify(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x86 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[1..])?; + let (value, value_len) = parse_term_arg(&data[1 + object_len..])?; + + Ok((Type1OpCode::DefNotify {object, value}, 1 + object_len + value_len)) +} + +fn parse_def_release(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x27 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefRelease(object), 2 + object_len)) +} + +fn parse_def_reset(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x26 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefReset(object), 2 + object_len)) +} + +fn parse_def_signal(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x24 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefSignal(object), 2 + object_len)) +} + +fn parse_def_sleep(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x22 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (time, time_len) = parse_term_arg(&data[2..])?; + + Ok((Type1OpCode::DefSleep(time), 2 + time_len)) +} + +fn parse_def_stall(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x21 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (time, time_len) = parse_term_arg(&data[2..])?; + + Ok((Type1OpCode::DefStall(time), 2 + time_len)) +} + +fn parse_def_unload(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x2A { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefUnload(object), 2 + object_len)) +} + +fn parse_def_if_else(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0xA0 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + + let if_block = match parse_term_arg(&data[1 + pkg_length_len..]) { + Ok((predicate, predicate_len)) => { + match parse_term_list(&data[1 + pkg_length_len + predicate_len .. 1 + pkg_length]) { + Ok(if_block) => IfBlock::If {predicate, if_block}, + Err(AmlInternalError::AmlDeferredLoad) => + IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + Err(e) => return Err(e) + } + }, + Err(AmlInternalError::AmlDeferredLoad) => + IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + Err(e) => return Err(e) + }; + + let (else_block, else_block_len) = parse_def_else(&data[1 + pkg_length..])?; + + return Ok((Type1OpCode::DefIfElse {if_block, else_block}, + pkg_length + else_block_len + 1)); +} + +fn parse_def_else(data: &[u8]) -> Result<(IfBlock, usize), AmlInternalError> { + if data.len() == 0 || data[0] != 0xA1 { + // We might be at the very end of a buffer, in which case there isn't an else + return Ok((IfBlock::NoBlock, 0)); + } + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + match parse_term_list(&data[1 + pkg_length_len .. 1 + pkg_length]) { + Ok(term_list) => Ok((IfBlock::Else(term_list), 1 + pkg_length)), + Err(AmlInternalError::AmlDeferredLoad) => + Ok((IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + } +} + +fn parse_def_while(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0xA2 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (predicate, predicate_len) = match parse_term_arg(&data[1 + pkg_length_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((Type1OpCode::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + }; + let block = match parse_term_list(&data[1 + pkg_length_len + predicate_len .. 1 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((Type1OpCode::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((Type1OpCode::DefWhile {predicate, block}, pkg_length + 1)) +} + +fn parse_def_return(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0xA4 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (arg_object, arg_object_len) = parse_term_arg(&data[1..])?; + + Ok((Type1OpCode::DefReturn(arg_object), 1 + arg_object_len)) +} diff --git a/src/acpi/aml/type2opcode.rs b/src/acpi/aml/type2opcode.rs new file mode 100644 index 0000000..744dbef --- /dev/null +++ b/src/acpi/aml/type2opcode.rs @@ -0,0 +1,932 @@ +use alloc::boxed::Box; +use collections::string::String; +use collections::vec::Vec; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; +use super::pkglength::parse_pkg_length; +use super::termlist::{parse_term_arg, parse_method_invocation, TermArg, MethodInvocation}; +use super::namestring::{parse_super_name, parse_target, parse_name_string, parse_simple_name, + SuperName, Target}; +use super::dataobj::{parse_data_ref_obj, DataRefObj}; + +#[derive(Debug, Clone)] +pub enum Type2OpCode { + DefAcquire { + object: SuperName, + timeout: u16 + }, + DefBuffer(DefBuffer), + DefPackage(DefPackage), + DefVarPackage(DefVarPackage), + DefDerefOf(TermArg), + DefRefOf(SuperName), + DefIncrement(SuperName), + DefIndex(DefIndex), + DefDecrement(SuperName), + DefFindSetLeftBit { + operand: TermArg, + target: Target + }, + DefFindSetRightBit { + operand: TermArg, + target: Target + }, + DefFromBCD { + operand: TermArg, + target: Target + }, + DefDivide { + dividend: TermArg, + divisor: TermArg, + remainder: Target, + quotient: Target + }, + DefCondRefOf { + operand: SuperName, + target: Target + }, + DefCopyObject { + source: TermArg, + destination: SuperName + }, + DefLAnd { + lhs: TermArg, + rhs: TermArg + }, + DefLEqual { + lhs: TermArg, + rhs: TermArg + }, + DefLGreater { + lhs: TermArg, + rhs: TermArg + }, + DefLLess { + lhs: TermArg, + rhs: TermArg + }, + DefLNot(TermArg), + DefLOr { + lhs: TermArg, + rhs: TermArg + }, + DefSizeOf(SuperName), + DefStore { + operand: TermArg, + target: SuperName + }, + DefSubtract { + minuend: TermArg, + subtrahend: TermArg, + target: Target + }, + DefToBuffer { + operand: TermArg, + target: Target + }, + DefToHexString { + operand: TermArg, + target: Target + }, + DefToBCD { + operand: TermArg, + target: Target + }, + DefToDecimalString { + operand: TermArg, + target: Target + }, + DefToInteger { + operand: TermArg, + target: Target + }, + DefToString { + operand: TermArg, + length: TermArg, + target: Target + }, + DefConcat { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefConcatRes { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefShiftLeft { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefShiftRight { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefAdd { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefMultiply { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefMod { + dividend: TermArg, + divisor: TermArg, + target: Target + }, + DefAnd { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefNAnd { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefOr { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefXor { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefNOr { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefNot { + operand: TermArg, + target: Target + }, + DefLoadTable { + signature: TermArg, + oem_id: TermArg, + oem_table_id: TermArg, + root_path: TermArg, + parameter_path: TermArg, + parameter_data: TermArg + }, + DefMatch { + search_pkg: TermArg, + first_operation: MatchOpcode, + first_operand: TermArg, + second_operation: MatchOpcode, + second_operand: TermArg, + start_index: TermArg + }, + DefMid { + source: TermArg, + index: TermArg, + length: TermArg, + target: Target + }, + DefWait { + event_object: SuperName, + operand: TermArg + }, + DefObjectType(DefObjectType), + DefTimer, + MethodInvocation(MethodInvocation) +} + +impl AmlExecutable for Type2OpCode { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + None + } +} + +#[derive(Debug, Clone)] +pub enum DefObjectType { + SuperName(SuperName), + DefIndex(DefIndex), + DefRefOf(SuperName), + DefDerefOf(TermArg) +} + +#[derive(Debug, Clone)] +pub enum MatchOpcode { + MTR, + MEQ, + MLE, + MLT, + MGE, + MGT +} + +#[derive(Debug, Clone)] +pub enum Type6OpCode { + DefDerefOf(TermArg), + DefRefOf(Box), + DefIndex(DefIndex), + MethodInvocation(MethodInvocation) +} + +#[derive(Debug, Clone)] +pub struct DefIndex { + obj: TermArg, + idx: TermArg, + target: Box +} + +#[derive(Debug, Clone)] +pub enum DefBuffer { + Buffer { + buffer_size: TermArg, + byte_list: Vec + }, + DeferredLoad(Vec) +} + +#[derive(Debug, Clone)] +pub enum DefPackage { + Package { + num_elements: u8, + elements: Vec + }, + DeferredLoad(Vec) +} + +#[derive(Debug, Clone)] +pub enum DefVarPackage { + Package { + num_elements: TermArg, + elements: Vec + }, + DeferredLoad(Vec) +} + +#[derive(Debug, Clone)] +pub enum PackageElement { + DataRefObj(DataRefObj), + NameString(String) +} + +impl AmlExecutable for DefPackage { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + DefPackage::Package { ref num_elements, ref elements } => { + let mut values: Vec = vec!(); + + for element in elements { + match *element { + PackageElement::DataRefObj(ref d) => { + let elem = match d.execute(namespace, scope.clone()) { + Some(e) => e, + None => continue + }; + + values.push(elem); + }, + _ => return None + } + } + + Some(AmlValue::Package(values)) + }, + _ => None + } + } +} + +pub fn parse_type2_opcode(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_selector! { + data, + parse_def_increment, + parse_def_acquire, + parse_def_wait, + parse_def_land, + parse_def_lequal, + parse_def_lgreater, + parse_def_lless, + parse_def_lnot, + parse_def_lor, + parse_def_size_of, + parse_def_store, + parse_def_subtract, + parse_def_to_buffer, + parse_def_to_hex_string, + parse_def_to_bcd, + parse_def_to_decimal_string, + parse_def_to_integer, + parse_def_to_string, + parse_def_add, + parse_def_xor, + parse_def_shift_left, + parse_def_shift_right, + parse_def_mod, + parse_def_and, + parse_def_or, + parse_def_concat_res, + parse_def_concat, + parse_def_cond_ref_of, + parse_def_copy_object, + parse_def_decrement, + parse_def_divide, + parse_def_find_set_left_bit, + parse_def_find_set_right_bit, + parse_def_from_bcd, + parse_def_load_table, + parse_def_match, + parse_def_mid, + parse_def_multiply, + parse_def_nand, + parse_def_nor, + parse_def_not, + parse_def_timer, + parser_wrap!(Type2OpCode::DefBuffer, parse_def_buffer), + parser_wrap!(Type2OpCode::DefPackage, parse_def_package), + parser_wrap!(Type2OpCode::DefVarPackage, parse_def_var_package), + parser_wrap!(Type2OpCode::DefObjectType, parse_def_object_type), + parser_wrap!(Type2OpCode::DefDerefOf, parse_def_deref_of), + parser_wrap!(Type2OpCode::DefRefOf, parse_def_ref_of), + parser_wrap!(Type2OpCode::DefIndex, parse_def_index), + parser_wrap!(Type2OpCode::MethodInvocation, parse_method_invocation) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_type6_opcode(data: &[u8]) -> Result<(Type6OpCode, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(Type6OpCode::DefDerefOf, parse_def_deref_of), + parser_wrap!(Type6OpCode::DefRefOf, parser_wrap!(Box::new, parse_def_ref_of)), + parser_wrap!(Type6OpCode::DefIndex, parse_def_index), + parser_wrap!(Type6OpCode::MethodInvocation, parse_method_invocation) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_def_object_type(data: &[u8]) -> Result<(DefObjectType, usize), AmlInternalError> { + parser_opcode!(data, 0x8E); + parser_selector! { + data, + parser_wrap!(DefObjectType::SuperName, parse_super_name), + parser_wrap!(DefObjectType::DefRefOf, parse_def_ref_of), + parser_wrap!(DefObjectType::DefDerefOf, parse_def_deref_of), + parser_wrap!(DefObjectType::DefIndex, parse_def_index) + } + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_def_package(data: &[u8]) -> Result<(DefPackage, usize), AmlInternalError> { + parser_opcode!(data, 0x12); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let num_elements = data[1 + pkg_length_len]; + + let elements = match parse_package_elements_list(&data[2 + pkg_length_len .. 1 + pkg_length]) { + Ok(e) => e, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((DefPackage::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((DefPackage::Package {num_elements, elements}, 1 + pkg_length)) +} + +pub fn parse_def_var_package(data: &[u8]) -> Result<(DefVarPackage, usize), AmlInternalError> { + parser_opcode!(data, 0x13); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (num_elements, num_elements_len) = parse_term_arg(&data[1 + pkg_length_len ..])?; + + let elements = match parse_package_elements_list(&data[1 + pkg_length_len + num_elements_len .. + 1 + pkg_length]) { + Ok(e) => e, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((DefVarPackage::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((DefVarPackage::Package {num_elements, elements}, 1 + pkg_length)) +} + +fn parse_package_elements_list(data: &[u8]) -> Result, AmlInternalError> { + let mut current_offset: usize = 0; + let mut elements: Vec = vec!(); + + while current_offset < data.len() { + match parse_data_ref_obj(&data[current_offset ..]) { + Ok((data_ref_obj, data_ref_obj_len)) => { + elements.push(PackageElement::DataRefObj(data_ref_obj)); + current_offset += data_ref_obj_len; + }, + Err(AmlInternalError::AmlInvalidOpCode) => + match parse_name_string(&data[current_offset ..]) { + Ok((name_string, name_string_len)) => { + elements.push(PackageElement::NameString(name_string)); + current_offset += name_string_len; + }, + Err(e) => return Err(e) + }, + Err(e) => return Err(e) + } + } + + Ok(elements) +} + +pub fn parse_def_buffer(data: &[u8]) -> Result<(DefBuffer, usize), AmlInternalError> { + parser_opcode!(data, 0x11); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (buffer_size, buffer_size_len) = match parse_term_arg(&data[1 + pkg_length_len..]) { + Ok(s) => s, + Err(AmlInternalError::AmlDeferredLoad) => return Ok((DefBuffer::DeferredLoad( + data[0 .. 1 + pkg_length].to_vec() + ), 1 + pkg_length)), + Err(e) => return Err(e), + }; + let byte_list = data[1 + pkg_length_len + buffer_size_len .. 1 + pkg_length].to_vec(); + + Ok((DefBuffer::Buffer {buffer_size, byte_list}, pkg_length + 1)) +} + +fn parse_def_ref_of(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_opcode!(data, 0x71); + let (obj_reference, obj_reference_len) = parse_super_name(&data[1..])?; + + Ok((obj_reference, obj_reference_len + 1)) +} + +fn parse_def_deref_of(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> { + parser_opcode!(data, 0x83); + let (obj_reference, obj_reference_len) = parse_term_arg(&data[1..])?; + + Ok((obj_reference, obj_reference_len + 1)) +} + +fn parse_def_acquire(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x23); + + let (object, object_len) = parse_super_name(&data[2..])?; + let timeout = (data[2 + object_len] as u16) + + ((data[3 + object_len] as u16) << 8); + + Ok((Type2OpCode::DefAcquire {object, timeout}, object_len + 4)) +} + +fn parse_def_increment(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x75); + + let (obj, obj_len) = parse_super_name(&data[1..])?; + Ok((Type2OpCode::DefIncrement(obj), obj_len + 1)) +} + +fn parse_def_index(data: &[u8]) -> Result<(DefIndex, usize), AmlInternalError> { + parser_opcode!(data, 0x88); + + let (obj, obj_len) = parse_term_arg(&data[1..])?; + let (idx, idx_len) = parse_term_arg(&data[1 + obj_len..])?; + let (target, target_len) = parse_target(&data[1 + obj_len + idx_len..])?; + + Ok((DefIndex {obj, idx, target: Box::new(target)}, 1 + obj_len + idx_len + target_len)) +} + +fn parse_def_land(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x90); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLAnd {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lequal(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x93); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLEqual {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lgreater(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x94); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLGreater {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lless(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x95); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLLess {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lnot(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x92); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + + Ok((Type2OpCode::DefLNot(operand), 1 + operand_len)) +} + +fn parse_def_lor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x91); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLOr {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_to_hex_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x98); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToHexString {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_buffer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x96); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToBuffer {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_bcd(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x29); + + let (operand, operand_len) = parse_term_arg(&data[2..])?; + let (target, target_len) = parse_target(&data[2 + operand_len..])?; + + Ok((Type2OpCode::DefToBCD {operand, target}, 2 + operand_len + target_len)) +} + +fn parse_def_to_decimal_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x97); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToDecimalString {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_integer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x99); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToInteger {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x9C); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (length, length_len) = parse_term_arg(&data[1 + operand_len..])?; + let (target, target_len) = parse_target(&data[1 + operand_len + length_len..])?; + + Ok((Type2OpCode::DefToString {operand, length, target}, 1 + operand_len + length_len + target_len)) +} + +fn parse_def_subtract(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x74); + + let (minuend, minuend_len) = parse_term_arg(&data[1..])?; + let (subtrahend, subtrahend_len) = parse_term_arg(&data[1 + minuend_len..])?; + let (target, target_len) = parse_target(&data[1 + minuend_len + subtrahend_len..])?; + + Ok((Type2OpCode::DefSubtract {minuend, subtrahend, target}, 1 + minuend_len + subtrahend_len + target_len)) +} + +fn parse_def_size_of(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x87); + + let (name, name_len) = parse_super_name(&data[1..])?; + Ok((Type2OpCode::DefSizeOf(name), name_len + 1)) +} + +fn parse_def_store(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x70); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_super_name(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefStore {operand, target}, operand_len + target_len + 1)) +} + +fn parse_def_or(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7D); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefOr {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_shift_left(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x79); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefShiftLeft {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_shift_right(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7A); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefShiftRight {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_add(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x72); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefAdd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_and(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7B); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefAnd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_xor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7F); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefXor {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_concat_res(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x84); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefConcatRes {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_wait(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x25); + + let (event_object, event_object_len) = parse_super_name(&data[2..])?; + let (operand, operand_len) = parse_term_arg(&data[2 + event_object_len..])?; + + + Ok((Type2OpCode::DefWait {event_object, operand}, 2 + event_object_len + operand_len)) +} + +fn parse_def_cond_ref_of(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x12); + + let (operand, operand_len) = parse_super_name(&data[2..])?; + let (target, target_len) = parse_target(&data[2 + operand_len..])?; + + Ok((Type2OpCode::DefCondRefOf {operand, target}, 2 + operand_len + target_len)) +} + +fn parse_def_copy_object(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x9D); + + let (source, source_len) = parse_term_arg(&data[1..])?; + let (destination, destination_len) = parse_simple_name(&data[1 + source_len..])?; + + Ok((Type2OpCode::DefCopyObject {source, destination}, 1 + source_len + destination_len)) +} + +fn parse_def_concat(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x73); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefConcat {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_decrement(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x76); + + let (target, target_len) = parse_super_name(&data[1..])?; + + Ok((Type2OpCode::DefDecrement(target), 1 + target_len)) +} + +fn parse_def_divide(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x78); + + let (dividend, dividend_len) = parse_term_arg(&data[1..])?; + let (divisor, divisor_len) = parse_term_arg(&data[1 + dividend_len..])?; + let (remainder, remainder_len) = parse_target(&data[1 + dividend_len + divisor_len..])?; + let (quotient, quotient_len) = parse_target(&data[1 + dividend_len + divisor_len + remainder_len..])?; + + Ok((Type2OpCode::DefDivide {dividend, divisor, remainder, quotient}, + 1 + dividend_len + divisor_len + remainder_len + quotient_len)) +} + +fn parse_def_find_set_left_bit(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x81); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefFindSetLeftBit {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_find_set_right_bit(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x82 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefFindSetRightBit {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_load_table(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x1F { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (signature, signature_len) = parse_term_arg(&data[2..])?; + let (oem_id, oem_id_len) = parse_term_arg(&data[2 + signature_len..])?; + let (oem_table_id, oem_table_id_len) = parse_term_arg(&data[2 + signature_len + oem_id_len..])?; + let (root_path, root_path_len) = + parse_term_arg(&data[2 + signature_len + oem_id_len + oem_table_id_len..])?; + let (parameter_path, parameter_path_len) = + parse_term_arg(&data[2 + signature_len + oem_id_len + oem_table_id_len + root_path_len..])?; + let (parameter_data, parameter_data_len) = + parse_term_arg(&data[2 + signature_len + oem_id_len + oem_table_id_len + root_path_len + + parameter_path_len..])?; + + Ok((Type2OpCode::DefLoadTable {signature, oem_id, oem_table_id, root_path, + parameter_path, parameter_data}, + 2 + signature_len + oem_id_len + oem_table_id_len + root_path_len + + parameter_path_len + parameter_data_len)) +} + +fn parse_def_match(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x89 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (search_pkg, search_pkg_len) = parse_term_arg(&data[1..])?; + let first_operation = match data[1 + search_pkg_len] { + 0 => MatchOpcode::MTR, + 1 => MatchOpcode::MEQ, + 2 => MatchOpcode::MLE, + 3 => MatchOpcode::MLT, + 4 => MatchOpcode::MGE, + 5 => MatchOpcode::MGT, + _ => return Err(AmlInternalError::AmlParseError("DefMatch - Invalid Opcode")) + }; + let (first_operand, first_operand_len) = parse_term_arg(&data[2 + search_pkg_len..])?; + + let second_operation = match data[2 + search_pkg_len + first_operand_len] { + 0 => MatchOpcode::MTR, + 1 => MatchOpcode::MEQ, + 2 => MatchOpcode::MLE, + 3 => MatchOpcode::MLT, + 4 => MatchOpcode::MGE, + 5 => MatchOpcode::MGT, + _ => return Err(AmlInternalError::AmlParseError("DefMatch - Invalid Opcode")) + }; + let (second_operand, second_operand_len) = + parse_term_arg(&data[3 + search_pkg_len + first_operand_len..])?; + + let (start_index, start_index_len) = + parse_term_arg(&data[3 + search_pkg_len + first_operand_len + second_operand_len..])?; + + Ok((Type2OpCode::DefMatch {search_pkg, first_operation, first_operand, + second_operation, second_operand, start_index}, + 3 + search_pkg_len + first_operand_len + second_operand_len + start_index_len)) +} + +fn parse_def_from_bcd(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x28 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (operand, operand_len) = parse_term_arg(&data[2..])?; + let (target, target_len) = parse_target(&data[2 + operand_len..])?; + + Ok((Type2OpCode::DefFromBCD {operand, target}, 2 + operand_len + target_len)) +} + +fn parse_def_mid(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x9E { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (source, source_len) = parse_term_arg(&data[1..])?; + let (index, index_len) = parse_term_arg(&data[1 + source_len..])?; + let (length, length_len) = parse_term_arg(&data[1 + source_len + index_len..])?; + let (target, target_len) = parse_target(&data[1 + source_len + index_len + length_len..])?; + + Ok((Type2OpCode::DefMid {source, index, length, target}, + 1 + source_len + index_len + length_len + target_len)) +} + +fn parse_def_mod(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x85 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (dividend, dividend_len) = parse_term_arg(&data[1..])?; + let (divisor, divisor_len) = parse_term_arg(&data[1 + dividend_len..])?; + let (target, target_len) = parse_target(&data[1 + dividend_len + divisor_len..])?; + + Ok((Type2OpCode::DefMod {dividend, divisor, target}, 1 + dividend_len + divisor_len + target_len)) +} + +fn parse_def_multiply(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x77 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefMultiply {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_nand(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x7C { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefNAnd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_nor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x7E { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefNOr {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_not(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x80 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefNot {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_timer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x33 { + return Err(AmlInternalError::AmlInvalidOpCode) + } + + Ok((Type2OpCode::DefTimer, 2 as usize)) +} diff --git a/src/acpi/dsdt.rs b/src/acpi/dsdt.rs deleted file mode 100644 index 67bcb7f..0000000 --- a/src/acpi/dsdt.rs +++ /dev/null @@ -1,78 +0,0 @@ -use core::slice; - -use super::sdt::Sdt; - -#[derive(Debug)] -pub struct Dsdt(&'static Sdt); - -impl Dsdt { - pub fn new(sdt: &'static Sdt) -> Option { - if &sdt.signature == b"DSDT" { - Some(Dsdt(sdt)) - } else { - None - } - } - - pub fn data(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.0.data_address() as *const u8, self.0.data_len()) } - } - - pub fn slp_typ(&self) -> Option<(u16, u16)> { - // Code from http://forum.osdev.org/viewtopic.php?t=16990, should be adapted - - let mut i = 0; - let data = self.data(); - - // search the \_S5 package in the DSDT - let s5_a = b"\x08_S5_\x12"; - let s5_b = b"\x08\\_S5_\x12"; - while i < data.len() { - if data[i..].starts_with(s5_a) { - i += s5_a.len(); - break; - } else if data[i..].starts_with(s5_b) { - i += s5_b.len(); - break; - } else { - i += 1; - } - } - - if i >= data.len() { - return None; - } - - // check if \_S5 was found - let pkglen = ((data[i] & 0xC0) >> 6) + 2; - i += pkglen as usize; - if i >= data.len() { - return None; - } - - if data[i] == 0x0A { - i += 1; // skip byteprefix - if i >= data.len() { - return None; - } - } - - let a = (data[i] as u16) << 10; - i += 1; - if i >= data.len() { - return None; - } - - if data[i] == 0x0A { - i += 1; // skip byteprefix - if i >= data.len() { - return None; - } - } - - let b = (data[i] as u16) << 10; - - Some((a, b)) - } - -} diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 4fe234a..98d9ba9 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -13,20 +13,21 @@ use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; use start::{kstart_ap, CPU_COUNT, AP_READY}; use self::dmar::{Dmar, DmarEntry}; -use self::dsdt::Dsdt; use self::fadt::Fadt; use self::madt::{Madt, MadtEntry}; use self::rsdt::Rsdt; use self::sdt::Sdt; use self::xsdt::Xsdt; +use self::aml::{is_aml_table, parse_aml_table, AmlNamespace, AmlError}; + mod dmar; -mod dsdt; mod fadt; mod madt; mod rsdt; mod sdt; mod xsdt; +mod aml; const TRAMPOLINE: usize = 0x7E00; const AP_STARTUP: usize = TRAMPOLINE + 512; @@ -70,9 +71,6 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { let dsdt = get_sdt(fadt.dsdt as usize, active_table); parse_sdt(dsdt, active_table); ACPI_TABLE.lock().fadt = Some(fadt); - } else if let Some(dsdt) = Dsdt::new(sdt) { - println!(": {}", dsdt.data().len()); - ACPI_TABLE.lock().dsdt = Some(dsdt); } else if let Some(madt) = Madt::new(sdt) { println!(": {:>08X}: {}", madt.local_address, madt.flags); @@ -197,6 +195,17 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { _ => () } } + } else if is_aml_table(sdt) { + ACPI_TABLE.lock().namespace = match parse_aml_table(sdt) { + Ok(res) => { + println!(": Parsed"); + Some(res) + }, + Err(AmlError::AmlParseError(e)) => { + println!(": {}", e); + None + } + }; } else { println!(": Unknown"); } @@ -259,10 +268,10 @@ pub unsafe fn init(active_table: &mut ActivePageTable) { pub struct Acpi { pub fadt: Option, - pub dsdt: Option, + pub namespace: Option, } -pub static ACPI_TABLE: Mutex = Mutex::new(Acpi { fadt: None, dsdt: None }); +pub static ACPI_TABLE: Mutex = Mutex::new(Acpi { fadt: None, namespace: None }); /// RSDP #[derive(Copy, Clone, Debug)] diff --git a/src/acpi/sdt.rs b/src/acpi/sdt.rs index 0d8cedd..62d55cf 100644 --- a/src/acpi/sdt.rs +++ b/src/acpi/sdt.rs @@ -1,4 +1,5 @@ use core::mem; +use core::slice; #[derive(Copy, Clone, Debug)] #[repr(packed)] @@ -30,4 +31,8 @@ impl Sdt { 0 } } + + pub fn data(&'static self) -> &[u8] { + unsafe { slice::from_raw_parts(self.data_address() as *const u8, self.data_len()) } + } } diff --git a/src/consts.rs b/src/consts.rs index 743bee5..149c9b4 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -15,7 +15,10 @@ /// Offset to kernel heap pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET + PML4_SIZE/2; /// Size of kernel heap - pub const KERNEL_HEAP_SIZE: usize = 256 * 1024 * 1024; // 256 MB + #[cfg(not(feature = "live"))] + pub const KERNEL_HEAP_SIZE: usize = 128 * 1024 * 1024; // 128 MB + #[cfg(feature = "live")] + pub const KERNEL_HEAP_SIZE: usize = 640 * 1024 * 1024; // 640 MB - 128 default + 512 for the live disk /// Offset to kernel percpu variables //TODO: Use 64-bit fs offset to enable this pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE; diff --git a/src/context/switch.rs b/src/context/switch.rs index c731929..4413d89 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -17,7 +17,6 @@ pub unsafe fn switch() -> bool { //set PIT Interrupt counter to 0, giving each process same amount of PIT ticks PIT_TICKS.store(0, Ordering::SeqCst); - assert_eq!(PIT_TICKS.load(Ordering::SeqCst), 0); // Set the global lock to avoid the unsafe operations below from causing issues while arch::CONTEXT_SWITCH_LOCK.compare_and_swap(false, true, Ordering::SeqCst) { diff --git a/src/elf.rs b/src/elf.rs index bf484fe..240cf56 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -4,11 +4,13 @@ use collections::String; use core::str; +use goblin::elf::section_header::SHT_SYMTAB; + #[cfg(target_arch = "x86")] -pub use goblin::elf32::{header, program_header}; +pub use goblin::elf32::{header, program_header, section_header, sym}; #[cfg(target_arch = "x86_64")] -pub use goblin::elf64::{header, program_header}; +pub use goblin::elf64::{header, program_header, section_header, sym}; /// An ELF executable pub struct Elf<'a> { @@ -33,6 +35,14 @@ impl<'a> Elf<'a> { } } + pub fn sections(&'a self) -> ElfSections<'a> { + ElfSections { + data: self.data, + header: self.header, + i: 0 + } + } + pub fn segments(&'a self) -> ElfSegments<'a> { ElfSegments { data: self.data, @@ -41,12 +51,58 @@ impl<'a> Elf<'a> { } } + pub fn symbols(&'a self) -> Option> { + let mut symtab_opt = None; + for section in self.sections() { + if section.sh_type == SHT_SYMTAB { + symtab_opt = Some(section); + break; + } + } + + if let Some(symtab) = symtab_opt { + Some(ElfSymbols { + data: self.data, + header: self.header, + symtab: symtab, + i: 0 + }) + } else { + None + } + } + /// Get the entry field of the header pub fn entry(&self) -> usize { self.header.e_entry as usize } } +pub struct ElfSections<'a> { + data: &'a [u8], + header: &'a header::Header, + i: usize +} + +impl<'a> Iterator for ElfSections<'a> { + type Item = &'a section_header::SectionHeader; + fn next(&mut self) -> Option { + if self.i < self.header.e_shnum as usize { + let item = unsafe { + &* (( + self.data.as_ptr() as usize + + self.header.e_shoff as usize + + self.i * self.header.e_shentsize as usize + ) as *const section_header::SectionHeader) + }; + self.i += 1; + Some(item) + } else { + None + } + } +} + pub struct ElfSegments<'a> { data: &'a [u8], header: &'a header::Header, @@ -71,3 +127,29 @@ impl<'a> Iterator for ElfSegments<'a> { } } } + +pub struct ElfSymbols<'a> { + data: &'a [u8], + header: &'a header::Header, + symtab: &'a section_header::SectionHeader, + i: usize +} + +impl<'a> Iterator for ElfSymbols<'a> { + type Item = &'a sym::Sym; + fn next(&mut self) -> Option { + if self.i < (self.symtab.sh_size as usize) / sym::SIZEOF_SYM { + let item = unsafe { + &* (( + self.data.as_ptr() as usize + + self.symtab.sh_offset as usize + + self.i * sym::SIZEOF_SYM + ) as *const sym::Sym) + }; + self.i += 1; + Some(item) + } else { + None + } + } +} diff --git a/src/interrupt/mod.rs b/src/interrupt/mod.rs index 3cc5caa..85686d9 100644 --- a/src/interrupt/mod.rs +++ b/src/interrupt/mod.rs @@ -1,13 +1,12 @@ //! Interrupt instructions -use core::mem; - -use paging::{ActivePageTable, VirtualAddress}; - pub mod exception; pub mod ipi; pub mod irq; pub mod syscall; +pub mod trace; + +pub use self::trace::stack_trace; /// Clear interrupts #[inline(always)] @@ -53,33 +52,3 @@ pub unsafe fn halt() { pub fn pause() { unsafe { asm!("pause" : : : : "intel", "volatile"); } } - -/// Get a stack trace -//TODO: Check for stack being mapped before dereferencing -#[inline(never)] -pub unsafe fn stack_trace() { - let mut rbp: usize; - asm!("" : "={rbp}"(rbp) : : : "intel", "volatile"); - - println!("TRACE: {:>016X}", rbp); - //Maximum 64 frames - let active_table = ActivePageTable::new(); - for _frame in 0..64 { - if let Some(rip_rbp) = rbp.checked_add(mem::size_of::()) { - if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rip_rbp)).is_some() { - let rip = *(rip_rbp as *const usize); - if rip == 0 { - println!(" {:>016X}: EMPTY RETURN", rbp); - break; - } - println!(" {:>016X}: {:>016X}", rbp, rip); - rbp = *(rbp as *const usize); - } else { - println!(" {:>016X}: GUARD PAGE", rbp); - break; - } - } else { - println!(" {:>016X}: RBP OVERFLOW", rbp); - } - } -} diff --git a/src/interrupt/trace.rs b/src/interrupt/trace.rs new file mode 100644 index 0000000..a2997ad --- /dev/null +++ b/src/interrupt/trace.rs @@ -0,0 +1,132 @@ +use core::{mem, str}; +use goblin::elf::sym; + +use paging::{ActivePageTable, VirtualAddress}; + +/// Get a stack trace +//TODO: Check for stack being mapped before dereferencing +#[inline(never)] +pub unsafe fn stack_trace() { + let mut rbp: usize; + asm!("" : "={rbp}"(rbp) : : : "intel", "volatile"); + + println!("TRACE: {:>016X}", rbp); + //Maximum 64 frames + let active_table = ActivePageTable::new(); + for _frame in 0..64 { + if let Some(rip_rbp) = rbp.checked_add(mem::size_of::()) { + if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rip_rbp)).is_some() { + let rip = *(rip_rbp as *const usize); + if rip == 0 { + println!(" {:>016X}: EMPTY RETURN", rbp); + break; + } + println!(" {:>016X}: {:>016X}", rbp, rip); + rbp = *(rbp as *const usize); + symbol_trace(rip); + } else { + println!(" {:>016X}: GUARD PAGE", rbp); + break; + } + } else { + println!(" {:>016X}: RBP OVERFLOW", rbp); + } + } +} + +/// Get a symbol +//TODO: Do not create Elf object for every symbol lookup +#[inline(never)] +pub unsafe fn symbol_trace(addr: usize) { + use core::slice; + use core::sync::atomic::Ordering; + + use elf::Elf; + use start::{KERNEL_BASE, KERNEL_SIZE}; + + let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + ::KERNEL_OFFSET) as *const u8; + let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst)); + if let Ok(elf) = Elf::from(kernel_slice) { + let mut strtab_opt = None; + for section in elf.sections() { + if section.sh_type == ::goblin::elf::section_header::SHT_STRTAB { + strtab_opt = Some(section); + break; + } + } + + if let Some(symbols) = elf.symbols() { + for sym in symbols { + if sym::st_type(sym.st_info) == sym::STT_FUNC + && addr >= sym.st_value as usize + && addr < (sym.st_value + sym.st_size) as usize + { + println!(" {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize); + + if let Some(strtab) = strtab_opt { + let start = strtab.sh_offset as usize + sym.st_name as usize; + let mut end = start; + while end < elf.data.len() { + let b = elf.data[end]; + end += 1; + if b == 0 { + break; + } + } + + if end > start { + let sym_name = &elf.data[start .. end]; + + print!(" "); + + if sym_name.starts_with(b"_ZN") { + // Skip _ZN + let mut i = 3; + let mut first = true; + while i < sym_name.len() { + // E is the end character + if sym_name[i] == b'E' { + break; + } + + // Parse length string + let mut len = 0; + while i < sym_name.len() { + let b = sym_name[i]; + if b >= b'0' && b <= b'9' { + i += 1; + len *= 10; + len += (b - b'0') as usize; + } else { + break; + } + } + + // Print namespace seperator, if required + if first { + first = false; + } else { + print!("::"); + } + + // Print name string + let end = i + len; + while i < sym_name.len() && i < end { + print!("{}", sym_name[i] as char); + i += 1; + } + } + } else { + for &b in sym_name.iter() { + print!("{}", b as char); + } + } + + println!(""); + } + } + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 678d8be..223a633 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ #![feature(alloc)] #![feature(asm)] #![feature(collections)] +#![feature(concat_idents)] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(drop_types_in_const)] diff --git a/src/memory/recycle.rs b/src/memory/recycle.rs index 21e0831..0932581 100644 --- a/src/memory/recycle.rs +++ b/src/memory/recycle.rs @@ -27,7 +27,6 @@ impl RecycleAllocator { for free in self.free.iter() { count += free.1; } - println!("Free count: {} in {} entries", count, self.free.len()); count } @@ -93,7 +92,7 @@ impl FrameAllocator for RecycleAllocator { if let Some(i) = small_i { let (address, remove) = { let free = &mut self.free[i]; - free.1 -= 1; + free.1 -= count; (free.0 + free.1 * 4096, free.1 == 0) }; diff --git a/src/paging/mapper.rs b/src/paging/mapper.rs index b3830bf..d0a5b29 100644 --- a/src/paging/mapper.rs +++ b/src/paging/mapper.rs @@ -89,11 +89,11 @@ impl Mapper { } pub fn p4(&self) -> &Table { - unsafe { self.p4.get() } + unsafe { self.p4.as_ref() } } pub fn p4_mut(&mut self) -> &mut Table { - unsafe { self.p4.get_mut() } + unsafe { self.p4.as_mut() } } /// Map a page to a frame @@ -137,50 +137,60 @@ impl Mapper { let frame; let p4 = self.p4_mut(); - { - let p3 = p4.next_table_mut(page.p4_index()).expect("unmap_inner: p3 not found"); - { - let p2 = p3.next_table_mut(page.p3_index()).expect("unmap_inner: p2 not found"); - { - let p1 = p2.next_table_mut(page.p2_index()).expect("unmap_inner: p1 not found"); + if let Some(p3) = p4.next_table_mut(page.p4_index()) { + if let Some(p2) = p3.next_table_mut(page.p3_index()) { + if let Some(p1) = p2.next_table_mut(page.p2_index()) { + frame = if let Some(frame) = p1[page.p1_index()].pointed_frame() { + frame + } else { + panic!("unmap_inner({:X}): frame not found", page.start_address().get()) + }; - frame = p1[page.p1_index()].pointed_frame().expect("unmap_inner: frame not found"); p1[page.p1_index()].set_unused(); if keep_parents || ! p1.is_unused() { return frame; } + } else { + panic!("unmap_inner({:X}): p1 not found", page.start_address().get()); } - { - let p1_frame = p2[page.p2_index()].pointed_frame().expect("unmap_inner: p1 frame not found"); + if let Some(p1_frame) = p2[page.p2_index()].pointed_frame() { //println!("Free p1 {:?}", p1_frame); p2[page.p2_index()].set_unused(); deallocate_frames(p1_frame, 1); + } else { + panic!("unmap_inner({:X}): p1_frame not found", page.start_address().get()); } if keep_parents || ! p2.is_unused() { return frame; } + } else { + panic!("unmap_inner({:X}): p2 not found", page.start_address().get()); } - { - let p2_frame = p3[page.p3_index()].pointed_frame().expect("unmap_inner: p2 frame not found"); + if let Some(p2_frame) = p3[page.p3_index()].pointed_frame() { //println!("Free p2 {:?}", p2_frame); p3[page.p3_index()].set_unused(); deallocate_frames(p2_frame, 1); + } else { + panic!("unmap_inner({:X}): p2_frame not found", page.start_address().get()); } if keep_parents || ! p3.is_unused() { return frame; } + } else { + panic!("unmap_inner({:X}): p3 not found", page.start_address().get()); } - { - let p3_frame = p4[page.p4_index()].pointed_frame().expect("unmap_inner: p3 frame not found"); + if let Some(p3_frame) = p4[page.p4_index()].pointed_frame() { //println!("Free p3 {:?}", p3_frame); p4[page.p4_index()].set_unused(); deallocate_frames(p3_frame, 1); + } else { + panic!("unmap_inner({:X}): p3_frame not found", page.start_address().get()); } frame diff --git a/src/paging/mod.rs b/src/paging/mod.rs index c293d55..caebefd 100644 --- a/src/paging/mod.rs +++ b/src/paging/mod.rs @@ -78,7 +78,7 @@ unsafe fn init_tcb(cpu_id: usize) -> usize { /// Initialize paging /// /// Returns page table and thread control block offset -pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (ActivePageTable, usize) { +pub unsafe fn init(cpu_id: usize, kernel_start: usize, kernel_end: usize, stack_start: usize, stack_end: usize) -> (ActivePageTable, usize) { extern { /// The starting byte of the text (code) data segment. static mut __text_start: u8; @@ -118,6 +118,60 @@ pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (Acti }; active_table.with(&mut new_table, &mut temporary_page, |mapper| { + // Remap stack writable, no execute + { + let start_frame = Frame::containing_address(PhysicalAddress::new(stack_start - ::KERNEL_OFFSET)); + let end_frame = Frame::containing_address(PhysicalAddress::new(stack_end - ::KERNEL_OFFSET - 1)); + for frame in Frame::range_inclusive(start_frame, end_frame) { + let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); + let result = mapper.map_to(page, frame, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); + // The flush can be ignored as this is not the active table. See later active_table.switch + unsafe { result.ignore(); } + } + } + + // Map all frames in kernel + { + let start_frame = Frame::containing_address(PhysicalAddress::new(kernel_start)); + let end_frame = Frame::containing_address(PhysicalAddress::new(kernel_end - 1)); + for frame in Frame::range_inclusive(start_frame, end_frame) { + let phys_addr = frame.start_address().get(); + let virt_addr = phys_addr + ::KERNEL_OFFSET; + + macro_rules! in_section { + ($n: ident) => ( + virt_addr >= & concat_idents!(__, $n, _start) as *const u8 as usize && + virt_addr < & concat_idents!(__, $n, _end) as *const u8 as usize + ); + } + + let flags = if in_section!(text) { + // Remap text read-only + PRESENT | GLOBAL + } else if in_section!(rodata) { + // Remap rodata read-only, no execute + PRESENT | GLOBAL | NO_EXECUTE + } else if in_section!(data) { + // Remap data writable, no execute + PRESENT | GLOBAL | NO_EXECUTE | WRITABLE + } else if in_section!(tdata) { + // Remap tdata master read-only, no execute + PRESENT | GLOBAL | NO_EXECUTE + } else if in_section!(bss) { + // Remap bss writable, no execute + PRESENT | GLOBAL | NO_EXECUTE | WRITABLE + } else { + // Remap anything else read-only, no execute + PRESENT | GLOBAL | NO_EXECUTE + }; + + let page = Page::containing_address(VirtualAddress::new(virt_addr)); + let result = mapper.map_to(page, frame, flags); + // The flush can be ignored as this is not the active table. See later active_table.switch + unsafe { result.ignore(); } + } + } + // Map tdata and tbss { let size = & __tbss_end as *const _ as usize - & __tdata_start as *const _ as usize; @@ -133,37 +187,6 @@ pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (Acti result.ignore(); } } - - let mut remap = |start: usize, end: usize, flags: EntryFlags| { - if end > start { - let start_frame = Frame::containing_address(PhysicalAddress::new(start)); - let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); - let result = mapper.map_to(page, frame, flags); - // The flush can be ignored as this is not the active table. See later active_table.switch - result.ignore(); - } - } - }; - - // Remap stack writable, no execute - remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - - // Remap a section with `flags` - let mut remap_section = |start: &u8, end: &u8, flags: EntryFlags| { - remap(start as *const _ as usize - ::KERNEL_OFFSET, end as *const _ as usize - ::KERNEL_OFFSET, flags); - }; - // Remap text read-only - remap_section(& __text_start, & __text_end, PRESENT | GLOBAL); - // Remap rodata read-only, no execute - remap_section(& __rodata_start, & __rodata_end, PRESENT | GLOBAL | NO_EXECUTE); - // Remap data writable, no execute - remap_section(& __data_start, & __data_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - // Remap tdata master writable, no execute - remap_section(& __tdata_start, & __tdata_end, PRESENT | GLOBAL | NO_EXECUTE); - // Remap bss writable, no execute - remap_section(& __bss_start, & __bss_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); }); // This switches the active table, which is setup by the bootloader, to a correct table diff --git a/src/panic.rs b/src/panic.rs index 27d361d..8ec88a8 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -4,12 +4,13 @@ use interrupt; #[cfg(not(test))] #[lang = "eh_personality"] -extern "C" fn eh_personality() {} +pub extern "C" fn eh_personality() {} #[cfg(not(test))] /// Required to handle panics #[lang = "panic_fmt"] -extern "C" fn panic_fmt(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! { +#[no_mangle] +pub extern "C" fn rust_begin_unwind(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! { println!("PANIC: {}", fmt); println!("FILE: {}", file); println!("LINE: {}", line); diff --git a/src/scheme/env.rs b/src/scheme/env.rs index d4a2973..062658c 100644 --- a/src/scheme/env.rs +++ b/src/scheme/env.rs @@ -7,7 +7,7 @@ use spin::{Mutex, RwLock}; use context; use syscall::data::Stat; use syscall::error::*; -use syscall::flag::{MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END}; +use syscall::flag::{MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END, O_CREAT}; use syscall::scheme::Scheme; #[derive(Clone)] @@ -32,7 +32,7 @@ impl EnvScheme { } impl Scheme for EnvScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { + fn open(&self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { let path = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/'); let env_lock = { @@ -69,11 +69,13 @@ impl Scheme for EnvScheme { let mut env = env_lock.lock(); if env.contains_key(path.as_bytes()) { env[path.as_bytes()].clone() - } else /*if flags & O_CREAT == O_CREAT*/ { + } else if flags & O_CREAT == O_CREAT { let name = path.as_bytes().to_vec().into_boxed_slice(); let data = Arc::new(Mutex::new(Vec::new())); env.insert(name, data.clone()); data + } else { + return Err(Error::new(ENOENT)); } }; @@ -211,4 +213,21 @@ impl Scheme for EnvScheme { fn close(&self, id: usize) -> Result { self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) } + + fn unlink(&self, path: &[u8], uid: u32, _gid: u32) -> Result { + let env_lock = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + context.env.clone() + }; + + let mut env = env_lock.lock(); + + if let Some(_) = env.remove(path) { + Ok(0) + } else { + Err(Error::new(ENOENT)) + } + } } diff --git a/src/scheme/live.rs b/src/scheme/live.rs index 905921f..e434f8e 100644 --- a/src/scheme/live.rs +++ b/src/scheme/live.rs @@ -11,7 +11,7 @@ use syscall::error::*; use syscall::flag::{MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::scheme::Scheme; -static FILESYSTEM: &'static [u8] = include_bytes!("../../../build/filesystem.bin"); +static FILESYSTEM: &'static [u8] = include_bytes!(env!("FILESYSTEM")); struct Handle { path: &'static [u8], diff --git a/src/scheme/root.rs b/src/scheme/root.rs index cd08fd3..42bcaad 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -14,7 +14,8 @@ pub struct RootScheme { scheme_ns: SchemeNamespace, scheme_id: SchemeId, next_id: AtomicUsize, - handles: RwLock>> + handles: RwLock>>, + ls_handles: RwLock>, } impl RootScheme { @@ -23,14 +24,26 @@ impl RootScheme { scheme_ns: scheme_ns, scheme_id: scheme_id, next_id: AtomicUsize::new(0), - handles: RwLock::new(BTreeMap::new()) + handles: RwLock::new(BTreeMap::new()), + ls_handles: RwLock::new(BTreeMap::new()), } } } impl Scheme for RootScheme { fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + use syscall::flag::*; + if uid == 0 { + if flags & O_DIRECTORY == O_DIRECTORY { + if flags & O_ACCMODE != O_RDONLY { + return Err(Error::new(EACCES)); + } + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.ls_handles.write().insert(id, AtomicUsize::new(0)); + return Ok(id); + } + let context = { let contexts = context::contexts(); let context = contexts.current().ok_or(Error::new(ESRCH))?; @@ -74,11 +87,46 @@ impl Scheme for RootScheme { fn read(&self, file: usize, buf: &mut [u8]) -> Result { let inner = { let handles = self.handles.read(); - let inner = handles.get(&file).ok_or(Error::new(EBADF))?; - inner.clone() + handles.get(&file).map(Clone::clone) }; - inner.read(buf) + if let Some(inner) = inner { + inner.read(buf) + } else { + let scheme_ns = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + context.ens + }; + + let schemes = scheme::schemes(); + let mut schemes_iter = schemes.iter_name(scheme_ns); + + let num = { + let handles = self.ls_handles.read(); + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; + inner.load(Ordering::SeqCst) + }; + + if let Some(scheme) = schemes_iter.nth(num) { + let mut i = 0; + while i < buf.len() && i < scheme.0.len() { + buf[i] = scheme.0[i]; + i += 1; + } + + { + let handles = self.ls_handles.read(); + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; + inner.fetch_add(1, Ordering::SeqCst) + }; + + Ok(i) + } else { + Ok(0) + } + } } fn write(&self, file: usize, buf: &[u8]) -> Result { @@ -136,6 +184,9 @@ impl Scheme for RootScheme { } fn close(&self, file: usize) -> Result { - self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) + if self.handles.write().remove(&file).is_none() { + self.ls_handles.write().remove(&file).ok_or(Error::new(EBADF))?; + } + Ok(0) } } diff --git a/src/start.rs b/src/start.rs index 2bf9f59..bf9deda 100644 --- a/src/start.rs +++ b/src/start.rs @@ -3,7 +3,6 @@ /// It must create the IDT with the correct entries, those entries are /// defined in other files inside of the `arch` module -use core::ptr; use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use acpi; @@ -27,6 +26,8 @@ static mut TBSS_TEST_ZERO: usize = 0; #[thread_local] static mut TDATA_TEST_NONZERO: usize = 0xFFFFFFFFFFFFFFFF; +pub static KERNEL_BASE: AtomicUsize = ATOMIC_USIZE_INIT; +pub static KERNEL_SIZE: AtomicUsize = ATOMIC_USIZE_INIT; pub static CPU_COUNT: AtomicUsize = ATOMIC_USIZE_INIT; pub static AP_READY: AtomicBool = ATOMIC_BOOL_INIT; static BSP_READY: AtomicBool = ATOMIC_BOOL_INIT; @@ -40,43 +41,28 @@ extern { /// The entry to Rust, all things must be initialized #[no_mangle] -pub unsafe extern fn kstart() -> ! { +pub unsafe extern fn kstart(kernel_base: usize, kernel_size: usize, stack_base: usize, stack_size: usize) -> ! { { - extern { - /// The starting byte of the _.bss_ (uninitialized data) segment. - static mut __bss_start: u8; - /// The ending byte of the _.bss_ (uninitialized data) segment. - static mut __bss_end: u8; - /// The end of the kernel - static mut __end: u8; - } - - // Zero BSS, this initializes statics that are set to 0 + // BSS should already be zero { - let start_ptr = &mut __bss_start as *mut u8; - let end_ptr = & __bss_end as *const u8 as usize; - - if start_ptr as usize <= end_ptr { - let size = end_ptr - start_ptr as usize; - ptr::write_bytes(start_ptr, 0, size); - } - assert_eq!(BSS_TEST_ZERO, 0); assert_eq!(DATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF); } - // Initialize memory management - memory::init(0, &__end as *const u8 as usize - ::KERNEL_OFFSET); + KERNEL_BASE.store(kernel_base, Ordering::SeqCst); + KERNEL_SIZE.store(kernel_size, Ordering::SeqCst); - // TODO: allocate a stack - let stack_start = 0x00080000 + ::KERNEL_OFFSET; - let stack_end = 0x0009F000 + ::KERNEL_OFFSET; + println!("Kernel: {:X}:{:X}", kernel_base, kernel_base + kernel_size); + println!("Stack: {:X}:{:X}", stack_base, stack_base + stack_size); + + // Initialize memory management + memory::init(0, kernel_base + ((kernel_size + 4095)/4096) * 4096); // Initialize paging - let (mut active_table, tcb_offset) = paging::init(0, stack_start, stack_end); + let (mut active_table, tcb_offset) = paging::init(0, kernel_base, kernel_base + kernel_size, stack_base, stack_base + stack_size); // Set up GDT - gdt::init(tcb_offset, stack_end); + gdt::init(tcb_offset, stack_base + stack_size); // Set up IDT idt::init(); diff --git a/src/stop.rs b/src/stop.rs index db2dfd6..7a9ac75 100644 --- a/src/stop.rs +++ b/src/stop.rs @@ -11,12 +11,18 @@ pub unsafe extern fn kstop() -> ! { if let Some(ref fadt) = acpi.fadt { let port = fadt.pm1a_control_block as u16; let mut val = 1 << 13; - if let Some(ref dsdt) = acpi.dsdt { - if let Some((a, b)) = dsdt.slp_typ() { - println!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", a, b); - val |= a; + if let Some(ref namespace) = acpi.namespace { + if let Some(s) = namespace.find_str("\\_S5") { + if let Some(p) = s.get_as_package() { + let slp_typa = p[0].get_as_integer().expect("SLP_TYPa is not an integer"); + let slp_typb = p[1].get_as_integer().expect("SLP_TYPb is not an integer"); + + println!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); + val |= slp_typa as u16; + } } } + println!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); Pio::::new(port).write(val); } diff --git a/src/syscall/process.rs b/src/syscall/process.rs index d202d46..8a86ba0 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -593,9 +593,12 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { let mut tls_option = None; for segment in elf.segments() { if segment.p_type == program_header::PT_LOAD { + let voff = segment.p_vaddr % 4096; + let vaddr = segment.p_vaddr - voff; + let mut memory = context::memory::Memory::new( - VirtualAddress::new(segment.p_vaddr as usize), - segment.p_memsz as usize, + VirtualAddress::new(vaddr as usize), + segment.p_memsz as usize + voff as usize, entry::NO_EXECUTE | entry::WRITABLE, true );