From bea674764359d6e523d7db5ca21697f97107d33f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 10 Mar 2021 12:33:11 +0100 Subject: [PATCH 1/9] Move all AML code to userspace. Currently, there are some things that need to be set up by userspace that the kernel previously did. These include telling firmware when the I/O APIC is used, and most importantly, shutting down the system. The former is not particularly important, but for the latter I think that we could implement this using a "shutdown pipe". Essentially it will be a file that triggers an event shutting down, which would be used to notify to acpid that the kernel is requesting a shutdown. --- Cargo.lock | 2 +- src/acpi/aml/dataobj.rs | 187 --- src/acpi/aml/mod.rs | 57 - src/acpi/aml/namedobj.rs | 1045 ----------------- src/acpi/aml/namespace.rs | 490 -------- src/acpi/aml/namespacemodifier.rs | 106 -- src/acpi/aml/namestring.rs | 226 ---- src/acpi/aml/parser.rs | 552 --------- src/acpi/aml/parsermacros.rs | 52 - src/acpi/aml/pkglength.rs | 25 - src/acpi/aml/termlist.rs | 174 --- src/acpi/aml/type1opcode.rs | 472 -------- src/acpi/aml/type2opcode.rs | 1779 ----------------------------- src/acpi/fadt.rs | 124 -- src/acpi/mod.rs | 121 +- src/acpi/rsdt.rs | 9 + src/acpi/xsdt.rs | 9 + src/arch/x86_64/device/ioapic.rs | 9 +- src/arch/x86_64/stop.rs | 7 +- src/lib.rs | 1 + src/scheme/acpi.rs | 471 ++------ 21 files changed, 156 insertions(+), 5762 deletions(-) delete mode 100644 src/acpi/aml/dataobj.rs delete mode 100644 src/acpi/aml/mod.rs delete mode 100644 src/acpi/aml/namedobj.rs delete mode 100644 src/acpi/aml/namespace.rs delete mode 100644 src/acpi/aml/namespacemodifier.rs delete mode 100644 src/acpi/aml/namestring.rs delete mode 100644 src/acpi/aml/parser.rs delete mode 100644 src/acpi/aml/parsermacros.rs delete mode 100644 src/acpi/aml/pkglength.rs delete mode 100644 src/acpi/aml/termlist.rs delete mode 100644 src/acpi/aml/type1opcode.rs delete mode 100644 src/acpi/aml/type2opcode.rs diff --git a/Cargo.lock b/Cargo.lock index 1e2bffd..2cb7f19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,7 +168,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.8" +version = "0.2.6" dependencies = [ "bitflags", ] diff --git a/src/acpi/aml/dataobj.rs b/src/acpi/aml/dataobj.rs deleted file mode 100644 index 32f8bf1..0000000 --- a/src/acpi/aml/dataobj.rs +++ /dev/null @@ -1,187 +0,0 @@ -use alloc::vec::Vec; -use alloc::string::String; - -use super::AmlError; -use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState }; -use super::namespace::{ AmlValue, ObjectReference }; - -use super::type2opcode::{parse_def_buffer, parse_def_package, parse_def_var_package}; -use super::termlist::parse_term_arg; -use super::namestring::parse_super_name; - -pub fn parse_data_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_computational_data, - parse_def_package, - parse_def_var_package - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_data_ref_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_data_obj, - parse_term_arg - }; - - match parse_super_name(data, ctx) { - Ok(res) => match res.val { - AmlValue::String(s) => Ok(AmlParseType { - val: AmlValue::ObjectReference(ObjectReference::Object(s)), - len: res.len - }), - _ => Ok(res) - }, - Err(e) => Err(e) - } -} - -pub fn parse_arg_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - match data[0] { - 0x68 ..= 0x6E => Ok(AmlParseType { - val: AmlValue::ObjectReference(ObjectReference::ArgObj(data[0] - 0x68)), - len: 1 as usize - }), - _ => Err(AmlError::AmlInvalidOpCode) - } -} - -pub fn parse_local_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - match data[0] { - 0x68 ..= 0x6E => Ok(AmlParseType { - val: AmlValue::ObjectReference(ObjectReference::LocalObj(data[0] - 0x60)), - len: 1 as usize - }), - _ => Err(AmlError::AmlInvalidOpCode) - } -} - -fn parse_computational_data(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - match data[0] { - 0x0A => Ok(AmlParseType { - val: AmlValue::Integer(data[1] as u64), - len: 2 as usize - }), - 0x0B => { - let res = (data[1] as u16) + - ((data[2] as u16) << 8); - - Ok(AmlParseType { - val: AmlValue::Integer(res as u64), - len: 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(AmlParseType { - val: AmlValue::Integer(res as u64), - len: 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(AmlParseType { - val: AmlValue::String(s.clone()), - len: s.clone().len() + 2 - }), - Err(_) => Err(AmlError::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(AmlParseType { - val: AmlValue::Integer(res as u64), - len: 9 as usize - }) - }, - 0x00 => Ok(AmlParseType { - val: AmlValue::IntegerConstant(0 as u64), - len: 1 as usize - }), - 0x01 => Ok(AmlParseType { - val: AmlValue::IntegerConstant(1 as u64), - len: 1 as usize - }), - 0x5B => if data[1] == 0x30 { - Ok(AmlParseType { - val: AmlValue::IntegerConstant(2017_0630 as u64), - len: 2 as usize - }) - } else { - Err(AmlError::AmlInvalidOpCode) - }, - 0xFF => Ok(AmlParseType { - val: AmlValue::IntegerConstant(0xFFFF_FFFF_FFFF_FFFF), - len: 1 as usize - }), - _ => parse_def_buffer(data, ctx) - } -} diff --git a/src/acpi/aml/mod.rs b/src/acpi/aml/mod.rs deleted file mode 100644 index 332e5fb..0000000 --- a/src/acpi/aml/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! # AML -//! Code to parse and execute AML tables - -use alloc::string::String; -use alloc::vec::Vec; -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; -mod parser; - -use self::parser::AmlExecutionContext; -use self::termlist::parse_term_list; -pub use self::namespace::AmlValue; - -#[derive(Debug)] -pub enum AmlError { - AmlParseError(&'static str), - AmlInvalidOpCode, - AmlValueError, - AmlDeferredLoad, - AmlFatalError(u8, u16, AmlValue), - AmlHardFatal -} - -pub fn parse_aml_table(sdt: &Sdt) -> Result, AmlError> { - parse_aml_with_scope(sdt, String::from_str("\\").unwrap()) -} - -pub fn parse_aml_with_scope(sdt: &Sdt, scope: String) -> Result, AmlError> { - let data = sdt.data(); - let mut ctx = AmlExecutionContext::new(scope); - - parse_term_list(data, &mut ctx)?; - - Ok(ctx.namespace_delta) -} - -pub fn is_aml_table(sdt: &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 deleted file mode 100644 index 2482fb7..0000000 --- a/src/acpi/aml/namedobj.rs +++ /dev/null @@ -1,1045 +0,0 @@ -use alloc::boxed::Box; -use alloc::string::String; -use alloc::collections::BTreeMap; - -use super::AmlError; -use super::parser::{ AmlParseType, ParseResult, AmlParseTypeGeneric, AmlExecutionContext, ExecutionState }; -use super::namespace::{AmlValue, FieldSelector, Method, get_namespace_string, - Accessor, BufferField, FieldUnit, Processor, PowerResource, OperationRegion, - Device, ThermalZone}; -use super::namestring::{parse_name_string, parse_name_seg}; -use super::termlist::{parse_term_arg, parse_object_list}; -use super::pkglength::parse_pkg_length; -use super::type2opcode::parse_def_buffer; - -#[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(AccessAttrib) -} - -#[derive(Debug, Clone)] -pub enum UpdateRule { - Preserve, - WriteAsOnes, - WriteAsZeros -} - -#[derive(Debug, Clone)] -pub struct NamedField { - name: String, - length: usize -} - -#[derive(Debug, Clone)] -pub struct AccessField { - access_type: AccessType, - access_attrib: AccessAttrib -} - -#[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], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - 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_external, - 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(AmlError::AmlInvalidOpCode) -} - -fn parse_def_bank_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 3 { - return Err(AmlError::AmlParseError("DefBankField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x87); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; - let data = &data[2 + pkg_length_len .. 2 + pkg_length]; - - let region_name = parse_name_string(data, ctx)?; - let bank_name = parse_name_string(&data[2 + pkg_length_len + region_name.len .. 2 + pkg_length], ctx)?; - - let bank_value = parse_term_arg(&data[2 + pkg_length_len + region_name.len .. 2 + pkg_length], ctx)?; - - let flags_raw = data[2 + pkg_length_len + region_name.len + bank_name.len + bank_value.len]; - let mut 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(AccessAttrib::AttribByte), - _ => return Err(AmlError::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(AmlError::AmlParseError("BankField - invalid update rule")) - } - }; - - let selector = FieldSelector::Bank { - region: region_name.val.get_as_string()?, - bank_register: bank_name.val.get_as_string()?, - bank_selector: Box::new(bank_value.val) - }; - - parse_field_list(&data[3 + pkg_length_len + region_name.len + bank_name.len + bank_value.len .. - 2 + pkg_length], ctx, selector, &mut flags)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_length - }) -} - -fn parse_def_create_bit_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateBitField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8D); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(1)) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_byte_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateByteField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8C); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(8)) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_word_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateWordField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8B); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(16)) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_dword_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateDwordField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8A); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - let _ = ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(32)) - })); - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_qword_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateQwordField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8F); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(64)) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x13); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let num_bits = parse_term_arg(&data[2 + source_buf.len + bit_index.len..], ctx)?; - let name = parse_name_string(&data[2 + source_buf.len + bit_index.len + num_bits.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(num_bits.val) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len + num_bits.len - }) -} - -fn parse_def_data_region(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefDataRegion - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Find the actual offset and length, once table mapping is implemented - parser_opcode_extended!(data, 0x88); - - let name = parse_name_string(&data[2..], ctx)?; - let signature = parse_term_arg(&data[2 + name.len..], ctx)?; - let oem_id = parse_term_arg(&data[2 + name.len + signature.len..], ctx)?; - let oem_table_id = parse_term_arg(&data[2 + name.len + signature.len + oem_id.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::OperationRegion(OperationRegion { - region: RegionSpace::SystemMemory, - offset: Box::new(AmlValue::IntegerConstant(0)), - len: Box::new(AmlValue::IntegerConstant(0)), - accessor: Accessor { - read: |_x| 0 as u64, - write: |_x, _y| () - }, - accessed_by: None - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + signature.len + oem_id.len + oem_table_id.len - }) -} - -fn parse_def_event(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefEvent - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x02); - - let name = parse_name_string(&data[2..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::Event(0))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len - }) -} - -fn parse_def_device(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefDevice - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: How to handle local context deferreds - parser_opcode_extended!(data, 0x82); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); - - parse_object_list(&data[2 + pkg_length_len + name.len .. 2 + pkg_length], &mut local_ctx)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::Device(Device { - obj_list: local_ctx.namespace_delta.clone(), - notify_methods: BTreeMap::new() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_length - }) -} - -fn parse_def_op_region(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 3 { - return Err(AmlError::AmlParseError("DefOpRegion - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x80); - - let name = parse_name_string(&data[2..], ctx)?; - 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(AmlError::AmlParseError("OpRegion - invalid region")) - }; - - let offset = parse_term_arg(&data[3 + name.len..], ctx)?; - let len = parse_term_arg(&data[3 + name.len + offset.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::OperationRegion(OperationRegion { - region: region, - offset: Box::new(offset.val), - len: Box::new(len.val), - accessor: Accessor { - read: |_x| 0 as u64, - write: |_x, _y| () - }, - accessed_by: None - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 3 + name.len + offset.len + len.len - }) -} - -fn parse_def_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 3 { - return Err(AmlError::AmlParseError("DefField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x81); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; - - let flags_raw = data[2 + pkg_length_len + name.len]; - let mut 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(AccessAttrib::AttribByte), - _ => return Err(AmlError::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(AmlError::AmlParseError("Field - Invalid update rule")) - } - }; - - let selector = FieldSelector::Region(name.val.get_as_string()?); - - parse_field_list(&data[3 + pkg_length_len + name.len .. 2 + pkg_length], ctx, selector, &mut flags)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_length - }) -} - -fn parse_def_index_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 3 { - return Err(AmlError::AmlParseError("DefIndexField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x86); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; - let idx_name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; - let data_name = parse_name_string(&data[2 + pkg_length_len + idx_name.len .. 2 + pkg_length], ctx)?; - - let flags_raw = data[2 + pkg_length_len + idx_name.len + data_name.len]; - let mut 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(AccessAttrib::AttribByte), - _ => return Err(AmlError::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(AmlError::AmlParseError("IndexField - Invalid update rule")) - } - }; - - let selector = FieldSelector::Index { - index_selector: idx_name.val.get_as_string()?, - data_selector: data_name.val.get_as_string()? - }; - - parse_field_list(&data[3 + pkg_length_len + idx_name.len + data_name.len .. 2 + pkg_length], - ctx, selector, &mut flags)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_length - }) -} - -fn parse_field_list(data: &[u8], - ctx: &mut AmlExecutionContext, - selector: FieldSelector, - flags: &mut FieldFlags) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let mut current_offset: usize = 0; - let mut field_offset: usize = 0; - let mut connection = AmlValue::Uninitialized; - - while current_offset < data.len() { - let res = parse_field_element(&data[current_offset..], ctx, selector.clone(), &mut connection, flags, &mut field_offset)?; - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - current_offset += res.len; - } - - Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) -} - -fn parse_field_element(data: &[u8], - ctx: &mut AmlExecutionContext, - selector: FieldSelector, - connection: &mut AmlValue, - flags: &mut FieldFlags, - offset: &mut usize) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let length = if let Ok(field) = parse_named_field(data, ctx) { - let local_scope_string = get_namespace_string(ctx.scope.clone(), AmlValue::String(field.val.name.clone()))?; - - ctx.add_to_namespace(local_scope_string, AmlValue::FieldUnit(FieldUnit { - selector: selector.clone(), - connection: Box::new(connection.clone()), - flags: flags.clone(), - offset: offset.clone(), - length: field.val.length - }))?; - - *offset += field.val.length; - field.len - } else if let Ok(field) = parse_reserved_field(data, ctx) { - *offset += field.val; - field.len - } else if let Ok(field) = parse_access_field(data, ctx) { - match field.val.access_type { - AccessType::BufferAcc(_) => - flags.access_type = AccessType::BufferAcc(field.val.access_attrib.clone()), - ref a => flags.access_type = a.clone() - } - - field.len - } else if let Ok(field) = parse_connect_field(data, ctx) { - *connection = field.val.clone(); - field.len - } else { - return Err(AmlError::AmlInvalidOpCode); - }; - - Ok(AmlParseType { - val: AmlValue::None, - len: length - }) -} - -fn parse_named_field(data: &[u8], _ctx: &mut AmlExecutionContext) -> Result, AmlError> { - if data.len() < 4 { - return Err(AmlError::AmlParseError("NamedField - data truncated")) - } - - 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(AmlError::AmlParseError("NamedField - invalid name")) - }; - let (length, length_len) = parse_pkg_length(&data[4..])?; - - Ok(AmlParseTypeGeneric { - val: NamedField { name, length }, - len: name_seg_len + length_len - }) -} - -fn parse_reserved_field(data: &[u8], _ctx: &mut AmlExecutionContext) -> Result, AmlError> { - if data.len() < 1 { - return Err(AmlError::AmlParseError("ReservedField - data truncated")) - } - - parser_opcode!(data, 0x00); - - let (length, length_len) = parse_pkg_length(&data[1..])?; - Ok(AmlParseTypeGeneric { - val: length, - len: 1 + length_len - }) -} - -fn parse_access_field(data: &[u8], _ctx: &mut AmlExecutionContext) -> Result, AmlError> { - if data.len() < 3 { - return Err(AmlError::AmlParseError("AccessField - data truncated")) - } - - 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(AccessAttrib::AttribByte), - _ => return Err(AmlError::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(AmlError::AmlParseError("AccessField - Invalid access attrib")) - }, - 1 => AccessAttrib::AttribBytes(data[2]), - 2 => AccessAttrib::AttribRawBytes(data[2]), - 3 => AccessAttrib::AttribRawProcessBytes(data[2]), - _ => return Err(AmlError::AmlParseError("AccessField - Invalid access attrib")) - // This should never happen but the compiler bitches if I don't cover this - }; - - Ok(AmlParseTypeGeneric { - val: AccessField { access_type, access_attrib }, - len: if data[0] == 0x01 { - 3 as usize - } else { - 4 as usize - } - }) -} - -fn parse_connect_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 1 { - return Err(AmlError::AmlParseError("ConnectField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x02); - - if let Ok(e) = parse_def_buffer(&data[1..], ctx) { - Ok(AmlParseType { - val: e.val, - len: e.len + 1 - }) - } else { - let name = parse_name_string(&data[1..], ctx)?; - Ok(AmlParseType { - val: AmlValue::Alias(name.val.get_as_string()?), - len: name.len + 1 - }) - } -} - -fn parse_def_method(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 1 { - return Err(AmlError::AmlParseError("DefMethod - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x14); - - let (pkg_len, pkg_len_len) = parse_pkg_length(&data[1..])?; - let name = parse_name_string(&data[1 + pkg_len_len..], ctx)?; - 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 = &data[2 + pkg_len_len + name.len .. 1 + pkg_len]; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::Method(Method { - arg_count, - serialized, - sync_level, - term_list: term_list.to_vec() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + pkg_len - }) -} - -fn parse_def_mutex(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 1 { - return Err(AmlError::AmlParseError("DefMutex - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x01); - - let name = parse_name_string(&data[2 ..], ctx)?; - let flags = data[2 + name.len]; - let sync_level = flags & 0x0F; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::Mutex((sync_level, None)))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 3 + name.len - }) -} - -fn parse_def_power_res(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 5 { - return Err(AmlError::AmlParseError("DefPowerRes - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: How to handle local context deferreds - parser_opcode_extended!(data, 0x84); - - let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - 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 mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); - parse_object_list(&data[5 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::PowerResource(PowerResource { - system_level, - resource_order, - obj_list: local_ctx.namespace_delta.clone() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_len - }) -} - -fn parse_def_processor(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 8 { - return Err(AmlError::AmlParseError("DefProcessor - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x83); - - let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - 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 mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); - parse_object_list(&data[8 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::Processor(Processor { - proc_id: proc_id, - p_blk: if p_blk_len > 0 { Some(p_blk_addr) } else { None }, - obj_list: local_ctx.namespace_delta.clone(), - notify_methods: BTreeMap::new() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_len - }) -} - -fn parse_def_thermal_zone(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefThermalZone - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x85); - - let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_len_len .. 2 + pkg_len], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); - parse_object_list(&data[2 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::ThermalZone(ThermalZone { - obj_list: local_ctx.namespace_delta.clone(), - notify_methods: BTreeMap::new() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_len - }) -} - -fn parse_def_external(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefExternal - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x15); - - let object_name = parse_name_string(&data[1..], ctx)?; - let object_type = data[1 + object_name.len]; - let argument_count = data[2 + object_name.len]; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), object_name.val)?; - - let obj = match object_type { - 8 => AmlValue::Method(Method { - arg_count: argument_count, - serialized: false, - sync_level: 0, - term_list: vec!() - }), - _ => AmlValue::Uninitialized - }; - - ctx.add_to_namespace(local_scope_string, obj)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 3 + object_name.len - }) -} diff --git a/src/acpi/aml/namespace.rs b/src/acpi/aml/namespace.rs deleted file mode 100644 index fef3b20..0000000 --- a/src/acpi/aml/namespace.rs +++ /dev/null @@ -1,490 +0,0 @@ -use alloc::boxed::Box; -use alloc::string::String; -use alloc::string::ToString; -use alloc::vec::Vec; -use alloc::collections::BTreeMap; - -use core::fmt::Debug; -use core::str::FromStr; - -use super::termlist::parse_term_list; -use super::namedobj::{ RegionSpace, FieldFlags }; -use super::parser::{AmlExecutionContext, ExecutionState}; -use super::AmlError; - -use crate::acpi::{SdtSignature, get_signature_from_index, get_index_from_signature}; - -#[derive(Clone, Debug)] -pub enum FieldSelector { - Region(String), - Bank { - region: String, - bank_register: String, - bank_selector: Box - }, - Index { - index_selector: String, - data_selector: String - } -} - -#[derive(Clone, Debug)] -pub enum ObjectReference { - ArgObj(u8), - LocalObj(u8), - Object(String), - Index(Box, Box) -} - -#[derive(Clone, Debug)] -pub struct Method { - pub arg_count: u8, - pub serialized: bool, - pub sync_level: u8, - pub term_list: Vec -} - -#[derive(Clone, Debug)] -pub struct BufferField { - pub source_buf: Box, - pub index: Box, - pub length: Box -} - -#[derive(Clone, Debug)] -pub struct FieldUnit { - pub selector: FieldSelector, - pub connection: Box, - pub flags: FieldFlags, - pub offset: usize, - pub length: usize -} - -#[derive(Clone, Debug)] -pub struct Device { - pub obj_list: Vec, - pub notify_methods: BTreeMap> -} - -#[derive(Clone, Debug)] -pub struct ThermalZone { - pub obj_list: Vec, - pub notify_methods: BTreeMap> -} - -#[derive(Clone, Debug)] -pub struct Processor { - pub proc_id: u8, - pub p_blk: Option, - pub obj_list: Vec, - pub notify_methods: BTreeMap> -} - -#[derive(Clone, Debug)] -pub struct OperationRegion { - pub region: RegionSpace, - pub offset: Box, - pub len: Box, - pub accessor: Accessor, - pub accessed_by: Option -} - -#[derive(Clone, Debug)] -pub struct PowerResource { - pub system_level: u8, - pub resource_order: u16, - pub obj_list: Vec -} - -#[derive(Debug)] -pub struct Accessor { - pub read: fn(usize) -> u64, - pub write: fn(usize, u64) -} - -impl Clone for Accessor { - fn clone(&self) -> Accessor { - Accessor { - read: (*self).read, - write: (*self).write - } - } -} - -#[derive(Clone, Debug)] -pub enum AmlValue { - None, - Uninitialized, - Alias(String), - Buffer(Vec), - BufferField(BufferField), - DDBHandle((Vec, SdtSignature)), - DebugObject, - Device(Device), - Event(u64), - FieldUnit(FieldUnit), - Integer(u64), - IntegerConstant(u64), - Method(Method), - Mutex((u8, Option)), - ObjectReference(ObjectReference), - OperationRegion(OperationRegion), - Package(Vec), - String(String), - PowerResource(PowerResource), - Processor(Processor), - RawDataBuffer(Vec), - ThermalZone(ThermalZone) -} - -impl AmlValue { - pub fn get_type_string(&self) -> String { - match *self { - AmlValue::Uninitialized => String::from_str("[Uninitialized Object]").unwrap(), - AmlValue::Integer(_) => String::from_str("[Integer]").unwrap(), - AmlValue::String(_) => String::from_str("[String]").unwrap(), - AmlValue::Buffer(_) => String::from_str("[Buffer]").unwrap(), - AmlValue::Package(_) => String::from_str("[Package]").unwrap(), - AmlValue::FieldUnit(_) => String::from_str("[Field]").unwrap(), - AmlValue::Device(_) => String::from_str("[Device]").unwrap(), - AmlValue::Event(_) => String::from_str("[Event]").unwrap(), - AmlValue::Method(_) => String::from_str("[Control Method]").unwrap(), - AmlValue::Mutex(_) => String::from_str("[Mutex]").unwrap(), - AmlValue::OperationRegion(_) => String::from_str("[Operation Region]").unwrap(), - AmlValue::PowerResource(_) => String::from_str("[Power Resource]").unwrap(), - AmlValue::Processor(_) => String::from_str("[Processor]").unwrap(), - AmlValue::ThermalZone(_) => String::from_str("[Thermal Zone]").unwrap(), - AmlValue::BufferField(_) => String::from_str("[Buffer Field]").unwrap(), - AmlValue::DDBHandle(_) => String::from_str("[DDB Handle]").unwrap(), - AmlValue::DebugObject => String::from_str("[Debug Object]").unwrap(), - _ => String::new() - } - } - - pub fn get_as_type(&self, t: AmlValue) -> Result { - match t { - AmlValue::None => Ok(AmlValue::None), - AmlValue::Uninitialized => Ok(self.clone()), - AmlValue::Alias(_) => match *self { - AmlValue::Alias(_) => Ok(self.clone()), - _ => Err(AmlError::AmlValueError) - }, - AmlValue::Buffer(_) => Ok(AmlValue::Buffer(self.get_as_buffer()?)), - AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field()?)), - AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle()?)), - AmlValue::DebugObject => match *self { - AmlValue::DebugObject => Ok(self.clone()), - _ => Err(AmlError::AmlValueError) - }, - AmlValue::Device(_) => Ok(AmlValue::Device(self.get_as_device()?)), - AmlValue::Event(_) => Ok(AmlValue::Event(self.get_as_event()?)), - AmlValue::FieldUnit(_) => Ok(AmlValue::FieldUnit(self.get_as_field_unit()?)), - AmlValue::Integer(_) => Ok(AmlValue::Integer(self.get_as_integer()?)), - AmlValue::IntegerConstant(_) => Ok(AmlValue::IntegerConstant(self.get_as_integer_constant()?)), - AmlValue::Method(_) => Ok(AmlValue::Method(self.get_as_method()?)), - AmlValue::Mutex(_) => Ok(AmlValue::Mutex(self.get_as_mutex()?)), - AmlValue::ObjectReference(_) => Ok(AmlValue::ObjectReference(self.get_as_object_reference()?)), - AmlValue::OperationRegion(_) => match *self { - AmlValue::OperationRegion(_) => Ok(self.clone()), - _ => Err(AmlError::AmlValueError) - }, - AmlValue::Package(_) => Ok(AmlValue::Package(self.get_as_package()?)), - AmlValue::String(_) => Ok(AmlValue::String(self.get_as_string()?)), - AmlValue::PowerResource(_) => Ok(AmlValue::PowerResource(self.get_as_power_resource()?)), - AmlValue::Processor(_) => Ok(AmlValue::Processor(self.get_as_processor()?)), - AmlValue::RawDataBuffer(_) => Ok(AmlValue::RawDataBuffer(self.get_as_raw_data_buffer()?)), - AmlValue::ThermalZone(_) => Ok(AmlValue::ThermalZone(self.get_as_thermal_zone()?)) - } - } - - pub fn get_as_buffer(&self) -> Result, AmlError> { - match *self { - AmlValue::Buffer(ref b) => Ok(b.clone()), - AmlValue::Integer(ref i) => { - let mut v: Vec = vec!(); - let mut i = i.clone(); - - while i != 0 { - v.push((i & 0xFF) as u8); - i >>= 8; - } - - while v.len() < 8 { - v.push(0); - } - - Ok(v) - }, - AmlValue::String(ref s) => { - Ok(s.clone().into_bytes()) - }, - AmlValue::BufferField(ref b) => { - let buf = b.source_buf.get_as_buffer()?; - let idx = b.index.get_as_integer()? as usize; - let len = b.length.get_as_integer()? as usize; - - if idx + len > buf.len() { - return Err(AmlError::AmlValueError); - } - - Ok(buf[idx .. idx + len].to_vec()) - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_buffer_field(&self) -> Result { - match *self { - AmlValue::BufferField(ref b) => Ok(b.clone()), - _ => { - let raw_buf = self.get_as_buffer()?; - let buf = Box::new(AmlValue::Buffer(raw_buf.clone())); - let idx = Box::new(AmlValue::IntegerConstant(0)); - let len = Box::new(AmlValue::Integer(raw_buf.len() as u64)); - - Ok(BufferField { - source_buf: buf, - index: idx, - length: len - }) - } - } - } - - pub fn get_as_ddb_handle(&self) -> Result<(Vec, SdtSignature), AmlError> { - match *self { - AmlValue::DDBHandle(ref v) => Ok(v.clone()), - AmlValue::Integer(i) => if let Some(sig) = get_signature_from_index(i as usize) { - Ok((vec!(), sig)) - } else { - Err(AmlError::AmlValueError) - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_device(&self) -> Result { - match *self { - AmlValue::Device(ref s) => Ok(s.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_event(&self) -> Result { - match *self { - AmlValue::Event(ref e) => Ok(e.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_field_unit(&self) -> Result { - match *self { - AmlValue::FieldUnit(ref e) => Ok(e.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_integer(&self) -> Result { - match *self { - AmlValue::IntegerConstant(ref i) => Ok(i.clone()), - AmlValue::Integer(ref i) => Ok(i.clone()), - AmlValue::Buffer(ref b) => { - let mut b = b.clone(); - if b.len() > 8 { - return Err(AmlError::AmlValueError); - } - - let mut i: u64 = 0; - - while b.len() > 0 { - i <<= 8; - i += b.pop().expect("Won't happen") as u64; - } - - Ok(i) - }, - AmlValue::BufferField(_) => { - let mut b = self.get_as_buffer()?; - if b.len() > 8 { - return Err(AmlError::AmlValueError); - } - - let mut i: u64 = 0; - - while b.len() > 0 { - i <<= 8; - i += b.pop().expect("Won't happen") as u64; - } - - Ok(i) - }, - AmlValue::DDBHandle(ref v) => if let Some(idx) = get_index_from_signature(v.1.clone()) { - Ok(idx as u64) - } else { - Err(AmlError::AmlValueError) - }, - AmlValue::String(ref s) => { - let s = s.clone()[0..8].to_string().to_uppercase(); - let mut i: u64 = 0; - - for c in s.chars() { - if !c.is_digit(16) { - break; - } - - i <<= 8; - i += c.to_digit(16).unwrap() as u64; - } - - Ok(i) - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_integer_constant(&self) -> Result { - match *self { - AmlValue::IntegerConstant(ref i) => Ok(i.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_method(&self) -> Result { - match *self { - AmlValue::Method(ref m) => Ok(m.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_mutex(&self) -> Result<(u8, Option), AmlError> { - match *self { - AmlValue::Mutex(ref m) => Ok(m.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_object_reference(&self) -> Result { - match *self { - AmlValue::ObjectReference(ref m) => Ok(m.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - /* - pub fn get_as_operation_region(&self) -> Result { - match *self { - AmlValue::OperationRegion(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - */ - - pub fn get_as_package(&self) -> Result, AmlError> { - match *self { - AmlValue::Package(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_string(&self) -> Result { - match *self { - AmlValue::String(ref s) => Ok(s.clone()), - AmlValue::Integer(ref i) => Ok(format!("{:X}", i)), - AmlValue::IntegerConstant(ref i) => Ok(format!("{:X}", i)), - AmlValue::Buffer(ref b) => Ok(String::from_utf8(b.clone()).expect("Invalid UTF-8")), - AmlValue::BufferField(_) => { - let b = self.get_as_buffer()?; - Ok(String::from_utf8(b).expect("Invalid UTF-8")) - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_power_resource(&self) -> Result { - match *self { - AmlValue::PowerResource(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_processor(&self) -> Result { - match *self { - AmlValue::Processor(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_raw_data_buffer(&self) -> Result, AmlError> { - match *self { - AmlValue::RawDataBuffer(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_thermal_zone(&self) -> Result { - match *self { - AmlValue::ThermalZone(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } -} - -impl Method { - pub fn execute(&self, scope: String, parameters: Vec) -> AmlValue { - let mut ctx = AmlExecutionContext::new(scope); - ctx.init_arg_vars(parameters); - - let _ = parse_term_list(&self.term_list[..], &mut ctx); - ctx.clean_namespace(); - - match ctx.state { - ExecutionState::RETURN(v) => v, - _ => AmlValue::IntegerConstant(0) - } - } -} - -pub fn get_namespace_string(current: String, modifier_v: AmlValue) -> Result { - let mut modifier = modifier_v.get_as_string()?; - - if current.len() == 0 { - return Ok(modifier); - } - - if modifier.len() == 0 { - return Ok(current); - } - - if modifier.starts_with("\\") { - return Ok(modifier); - } - - let mut namespace = current.clone(); - - if modifier.starts_with("^") { - while modifier.starts_with("^") { - modifier = modifier[1..].to_string(); - - if namespace.ends_with("\\") { - return Err(AmlError::AmlValueError); - } - - loop { - if namespace.ends_with(".") { - namespace.pop(); - break; - } - - if namespace.pop() == None { - return Err(AmlError::AmlValueError); - } - } - } - } - - if !namespace.ends_with("\\") { - namespace.push('.'); - } - - Ok(namespace + &modifier) -} diff --git a/src/acpi/aml/namespacemodifier.rs b/src/acpi/aml/namespacemodifier.rs deleted file mode 100644 index 77fa140..0000000 --- a/src/acpi/aml/namespacemodifier.rs +++ /dev/null @@ -1,106 +0,0 @@ -use super::AmlError; -use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; -use super::namespace::{AmlValue, get_namespace_string}; -use super::pkglength::parse_pkg_length; -use super::namestring::parse_name_string; -use super::termlist::parse_term_list; -use super::dataobj::parse_data_ref_obj; - -pub fn parse_namespace_modifier(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_alias_op, - parse_scope_op, - parse_name_op - }; - - Err(AmlError::AmlInvalidOpCode) -} - -fn parse_alias_op(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x06); - - let source_name = parse_name_string(&data[1..], ctx)?; - let alias_name = parse_name_string(&data[1 + source_name.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), source_name.val)?; - let local_alias_string = get_namespace_string(ctx.scope.clone(), alias_name.val)?; - - ctx.add_to_namespace(local_scope_string, AmlValue::Alias(local_alias_string))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + source_name.len + alias_name.len - }) -} - -fn parse_name_op(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x08); - - let name = parse_name_string(&data[1..], ctx)?; - let data_ref_obj = parse_data_ref_obj(&data[1 + name.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(local_scope_string, data_ref_obj.val)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + name.len + data_ref_obj.len - }) -} - -fn parse_scope_op(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x10); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let name = parse_name_string(&data[1 + pkg_length_len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val.clone())?; - let containing_scope_string = ctx.scope.clone(); - - ctx.scope = local_scope_string; - parse_term_list(&data[1 + pkg_length_len + name.len .. 1 + pkg_length], ctx)?; - ctx.scope = containing_scope_string; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + pkg_length - }) -} diff --git a/src/acpi/aml/namestring.rs b/src/acpi/aml/namestring.rs deleted file mode 100644 index 3cc8238..0000000 --- a/src/acpi/aml/namestring.rs +++ /dev/null @@ -1,226 +0,0 @@ -use alloc::vec::Vec; -use alloc::string::String; - -use super::AmlError; -use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; -use super::namespace::AmlValue; -use super::dataobj::{parse_arg_obj, parse_local_obj}; -use super::type2opcode::parse_type6_opcode; - -pub fn parse_name_string(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - 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_simple! { - data, - parse_dual_name_path, - parse_multi_name_path, - parse_null_name, - parse_name_seg - }; - - Err(AmlError::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(AmlParseType { - val: AmlValue::String(s.clone()), - len: len + starting_index - }), - Err(_) => Err(AmlError::AmlParseError("Namestring - Name is invalid")) - } -} - -fn parse_null_name(data: &[u8]) -> Result<(Vec, usize), AmlError> { - parser_opcode!(data, 0x00); - Ok((vec!(), 1 )) -} - -pub fn parse_name_seg(data: &[u8]) -> Result<(Vec, usize), AmlError> { - match data[0] { - 0x41 ..= 0x5A | 0x5F => (), - _ => return Err(AmlError::AmlInvalidOpCode) - } - - match data[1] { - 0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (), - _ => return Err(AmlError::AmlInvalidOpCode) - } - - match data[2] { - 0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (), - _ => return Err(AmlError::AmlInvalidOpCode) - } - - match data[3] { - 0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (), - _ => return Err(AmlError::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)) -} - -fn parse_dual_name_path(data: &[u8]) -> Result<(Vec, usize), AmlError> { - 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), AmlError> { - parser_opcode!(data, 0x2F); - - let seg_count = data[1]; - if seg_count == 0x00 { - return Err(AmlError::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], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_simple_name, - parse_type6_opcode, - parse_debug_obj - }; - - Err(AmlError::AmlInvalidOpCode) -} - -fn parse_debug_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x31); - - Ok(AmlParseType { - val: AmlValue::DebugObject, - len: 2 - }) -} - -pub fn parse_simple_name(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_name_string, - parse_arg_obj, - parse_local_obj - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_target(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - if data[0] == 0x00 { - Ok(AmlParseType { - val: AmlValue::None, - len: 1 - }) - } else { - parse_super_name(data, ctx) - } -} diff --git a/src/acpi/aml/parser.rs b/src/acpi/aml/parser.rs deleted file mode 100644 index b1046e2..0000000 --- a/src/acpi/aml/parser.rs +++ /dev/null @@ -1,552 +0,0 @@ -use alloc::string::String; -use alloc::collections::BTreeMap; -use alloc::vec::Vec; -use alloc::boxed::Box; - -use spin::RwLockWriteGuard; - -use super::namespace::{ AmlValue, ObjectReference }; -use super::AmlError; - -use crate::acpi::ACPI_TABLE; - -pub type ParseResult = Result; -pub type AmlParseType = AmlParseTypeGeneric; - -pub struct AmlParseTypeGeneric { - pub val: T, - pub len: usize -} - -pub enum ExecutionState { - EXECUTING, - CONTINUE, - BREAK, - RETURN(AmlValue) -} - -pub struct AmlExecutionContext { - pub scope: String, - pub local_vars: [AmlValue; 8], - pub arg_vars: [AmlValue; 8], - pub state: ExecutionState, - pub namespace_delta: Vec, - pub ctx_id: u64, - pub sync_level: u8 -} - -impl AmlExecutionContext { - pub fn new(scope: String) -> AmlExecutionContext { - let mut idptr = ACPI_TABLE.next_ctx.write(); - let id: u64 = *idptr; - - *idptr += 1; - - AmlExecutionContext { - scope: scope, - local_vars: [AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized], - arg_vars: [AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized], - state: ExecutionState::EXECUTING, - namespace_delta: vec!(), - ctx_id: id, - sync_level: 0 - } - } - - pub fn wait_for_event(&mut self, event_ptr: AmlValue) -> Result { - let mut namespace_ptr = self.prelock(); - let namespace = match *namespace_ptr { - Some(ref mut n) => n, - None => return Err(AmlError::AmlHardFatal) - }; - - let mutex_idx = match event_ptr { - AmlValue::String(ref s) => s.clone(), - AmlValue::ObjectReference(ref o) => match *o { - ObjectReference::Object(ref s) => s.clone(), - _ => return Err(AmlError::AmlValueError) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let mutex = match namespace.get(&mutex_idx) { - Some(s) => s.clone(), - None => return Err(AmlError::AmlValueError) - }; - - match mutex { - AmlValue::Event(count) => { - if count > 0 { - namespace.insert(mutex_idx, AmlValue::Event(count - 1)); - return Ok(true); - } - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(false) - } - - pub fn signal_event(&mut self, event_ptr: AmlValue) -> Result<(), AmlError> { - let mut namespace_ptr = self.prelock(); - let namespace = match *namespace_ptr { - Some(ref mut n) => n, - None => return Err(AmlError::AmlHardFatal) - }; - - - let mutex_idx = match event_ptr { - AmlValue::String(ref s) => s.clone(), - AmlValue::ObjectReference(ref o) => match *o { - ObjectReference::Object(ref s) => s.clone(), - _ => return Err(AmlError::AmlValueError) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let mutex = match namespace.get(&mutex_idx) { - Some(s) => s.clone(), - None => return Err(AmlError::AmlValueError) - }; - - match mutex { - AmlValue::Event(count) => { - namespace.insert(mutex_idx, AmlValue::Event(count + 1)); - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(()) - } - - pub fn release_mutex(&mut self, mutex_ptr: AmlValue) -> Result<(), AmlError> { - let id = self.ctx_id; - - let mut namespace_ptr = self.prelock(); - let namespace = match *namespace_ptr { - Some(ref mut n) => n, - None => return Err(AmlError::AmlHardFatal) - }; - - let mutex_idx = match mutex_ptr { - AmlValue::String(ref s) => s.clone(), - AmlValue::ObjectReference(ref o) => match *o { - ObjectReference::Object(ref s) => s.clone(), - _ => return Err(AmlError::AmlValueError) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let mutex = match namespace.get(&mutex_idx) { - Some(s) => s.clone(), - None => return Err(AmlError::AmlValueError) - }; - - match mutex { - AmlValue::Mutex((sync_level, owner)) => { - if let Some(o) = owner { - if o == id { - if sync_level == self.sync_level { - namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, None))); - return Ok(()); - } else { - return Err(AmlError::AmlValueError); - } - } else { - return Err(AmlError::AmlHardFatal); - } - } - }, - AmlValue::OperationRegion(ref region) => { - if let Some(o) = region.accessed_by { - if o == id { - let mut new_region = region.clone(); - new_region.accessed_by = None; - - namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region)); - return Ok(()); - } else { - return Err(AmlError::AmlHardFatal); - } - } - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(()) - } - - pub fn acquire_mutex(&mut self, mutex_ptr: AmlValue) -> Result { - let id = self.ctx_id; - - let mut namespace_ptr = self.prelock(); - let namespace = match *namespace_ptr { - Some(ref mut n) => n, - None => return Err(AmlError::AmlHardFatal) - }; - let mutex_idx = match mutex_ptr { - AmlValue::String(ref s) => s.clone(), - AmlValue::ObjectReference(ref o) => match *o { - ObjectReference::Object(ref s) => s.clone(), - _ => return Err(AmlError::AmlValueError) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let mutex = match namespace.get(&mutex_idx) { - Some(s) => s.clone(), - None => return Err(AmlError::AmlValueError) - }; - - match mutex { - AmlValue::Mutex((sync_level, owner)) => { - if owner == None { - if sync_level < self.sync_level { - return Err(AmlError::AmlValueError); - } - - namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, Some(id)))); - self.sync_level = sync_level; - - return Ok(true); - } - }, - AmlValue::OperationRegion(ref o) => { - if o.accessed_by == None { - let mut new_region = o.clone(); - new_region.accessed_by = Some(id); - - namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region)); - return Ok(true); - } - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(false) - } - - pub fn add_to_namespace(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { - let mut namespace = ACPI_TABLE.namespace.write(); - - if let Some(ref mut namespace) = *namespace { - if let Some(obj) = namespace.get(&name) { - match *obj { - AmlValue::Uninitialized => (), - AmlValue::Method(ref m) => { - if m.term_list.len() != 0 { - return Err(AmlError::AmlValueError); - } - }, - _ => return Err(AmlError::AmlValueError) - } - } - - self.namespace_delta.push(name.clone()); - namespace.insert(name, value); - - Ok(()) - } else { - Err(AmlError::AmlValueError) - } - } - - pub fn clean_namespace(&mut self) { - let mut namespace = ACPI_TABLE.namespace.write(); - - if let Some(ref mut namespace) = *namespace { - for k in &self.namespace_delta { - namespace.remove(k); - } - } - } - - pub fn init_arg_vars(&mut self, parameters: Vec) { - if parameters.len() > 8 { - return; - } - - let mut cur = 0; - while cur < parameters.len() { - self.arg_vars[cur] = parameters[cur].clone(); - cur += 1; - } - } - - pub fn prelock(&mut self) -> RwLockWriteGuard<'static, Option>> { - ACPI_TABLE.namespace.write() - } - - fn modify_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> { - self.local_vars[local] = value.get_as_type(self.local_vars[local].clone())?; - Ok(()) - } - - fn modify_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { - if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { - let coercion_obj = { - let obj = namespace.get(&name); - - if let Some(o) = obj { - o.clone() - } else { - AmlValue::Uninitialized - } - }; - - namespace.insert(name, value.get_as_type(coercion_obj)?); - Ok(()) - } else { - Err(AmlError::AmlHardFatal) - } - } - - fn modify_index_final(&mut self, name: String, value: AmlValue, indices: Vec) -> Result<(), AmlError> { - if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { - let mut obj = if let Some(s) = namespace.get(&name) { - s.clone() - } else { - return Err(AmlError::AmlValueError); - }; - - obj = self.modify_index_core(obj, value, indices)?; - - namespace.insert(name, obj); - Ok(()) - } else { - Err(AmlError::AmlValueError) - } - } - - fn modify_index_core(&mut self, obj: AmlValue, value: AmlValue, indices: Vec) -> Result { - match obj { - AmlValue::String(ref string) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let mut bytes = string.clone().into_bytes(); - bytes[indices[0] as usize] = value.get_as_integer()? as u8; - - let string = String::from_utf8(bytes).unwrap(); - - Ok(AmlValue::String(string)) - }, - AmlValue::Buffer(ref b) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let mut b = b.clone(); - b[indices[0] as usize] = value.get_as_integer()? as u8; - - Ok(AmlValue::Buffer(b)) - }, - AmlValue::BufferField(ref b) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let mut idx = indices[0]; - idx += b.index.get_as_integer()?; - - let _ = self.modify(AmlValue::ObjectReference(ObjectReference::Index(b.source_buf.clone(), Box::new(AmlValue::Integer(idx.clone())))), value); - - Ok(AmlValue::BufferField(b.clone())) - }, - AmlValue::Package(ref p) => { - if indices.len() == 0 { - return Err(AmlError::AmlValueError); - } - - let mut p = p.clone(); - - if indices.len() == 1 { - p[indices[0] as usize] = value; - } else { - p[indices[0] as usize] = self.modify_index_core(p[indices[0] as usize].clone(), value, indices[1..].to_vec())?; - } - - Ok(AmlValue::Package(p)) - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn modify_index(&mut self, name: AmlValue, value: AmlValue, indices: Vec) -> Result<(), AmlError>{ - match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::Object(s) => self.modify_index_final(s, value, indices), - ObjectReference::Index(c, v) => { - let mut indices = indices.clone(); - indices.push(v.get_as_integer()?); - - self.modify_index(*c, value, indices) - }, - ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), - ObjectReference::LocalObj(i) => { - let v = self.local_vars[i as usize].clone(); - self.local_vars[i as usize] = self.modify_index_core(v, value, indices)?; - - Ok(()) - } - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn modify(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { - match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), - ObjectReference::LocalObj(i) => self.modify_local_obj(i as usize, value), - ObjectReference::Object(s) => self.modify_object(s, value), - ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?)) - }, - AmlValue::String(s) => self.modify_object(s, value), - _ => Err(AmlError::AmlValueError) - } - } - - fn copy_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> { - self.local_vars[local] = value; - Ok(()) - } - - fn copy_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { - if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { - namespace.insert(name, value); - Ok(()) - } else { - Err(AmlError::AmlHardFatal) - } - } - - pub fn copy(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { - match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), - ObjectReference::LocalObj(i) => self.copy_local_obj(i as usize, value), - ObjectReference::Object(s) => self.copy_object(s, value), - ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?)) - }, - AmlValue::String(s) => self.copy_object(s, value), - _ => Err(AmlError::AmlValueError) - } - } - - fn get_index_final(&self, name: String, indices: Vec) -> Result { - if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { - let obj = if let Some(s) = namespace.get(&name) { - s.clone() - } else { - return Err(AmlError::AmlValueError); - }; - - self.get_index_core(obj, indices) - } else { - Err(AmlError::AmlValueError) - } - } - - fn get_index_core(&self, obj: AmlValue, indices: Vec) -> Result { - match obj { - AmlValue::String(ref string) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let bytes = string.clone().into_bytes(); - Ok(AmlValue::Integer(bytes[indices[0] as usize] as u64)) - }, - AmlValue::Buffer(ref b) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - Ok(AmlValue::Integer(b[indices[0] as usize] as u64)) - }, - AmlValue::BufferField(ref b) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let mut idx = indices[0]; - idx += b.index.get_as_integer()?; - - Ok(AmlValue::Integer(b.source_buf.get_as_buffer()?[idx as usize] as u64)) - }, - AmlValue::Package(ref p) => { - if indices.len() == 0 { - return Err(AmlError::AmlValueError); - } - - if indices.len() == 1 { - Ok(p[indices[0] as usize].clone()) - } else { - self.get_index_core(p[indices[0] as usize].clone(), indices[1..].to_vec()) - } - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_index(&self, name: AmlValue, indices: Vec) -> Result{ - match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::Object(s) => self.get_index_final(s, indices), - ObjectReference::Index(c, v) => { - let mut indices = indices.clone(); - indices.push(v.get_as_integer()?); - - self.get_index(*c, indices) - }, - ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), - ObjectReference::LocalObj(i) => { - let v = self.local_vars[i as usize].clone(); - self.get_index_core(v, indices) - } - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get(&self, name: AmlValue) -> Result { - Ok(match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::ArgObj(i) => self.arg_vars[i as usize].clone(), - ObjectReference::LocalObj(i) => self.local_vars[i as usize].clone(), - ObjectReference::Object(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { - if let Some(o) = namespace.get(s) { - o.clone() - } else { - AmlValue::None - } - } else { AmlValue::None }, - ObjectReference::Index(c, v) => self.get_index(*c, vec!(v.get_as_integer()?))?, - }, - AmlValue::String(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { - if let Some(o) = namespace.get(s) { - o.clone() - } else { - AmlValue::None - } - } else { AmlValue::None }, - _ => AmlValue::None - }) - } -} diff --git a/src/acpi/aml/parsermacros.rs b/src/acpi/aml/parsermacros.rs deleted file mode 100644 index 31a2338..0000000 --- a/src/acpi/aml/parsermacros.rs +++ /dev/null @@ -1,52 +0,0 @@ -#[macro_export] -macro_rules! parser_selector { - {$data:expr, $ctx:expr, $func:expr} => { - match $func($data, $ctx) { - Ok(res) => return Ok(res), - Err(AmlError::AmlInvalidOpCode) => (), - Err(e) => return Err(e) - } - }; - {$data:expr, $ctx:expr, $func:expr, $($funcs:expr),+} => { - parser_selector! {$data, $ctx, $func}; - parser_selector! {$data, $ctx, $($funcs),*}; - }; -} - -#[macro_export] -macro_rules! parser_selector_simple { - {$data:expr, $func:expr} => { - match $func($data) { - Ok(res) => return Ok(res), - Err(AmlError::AmlInvalidOpCode) => (), - Err(e) => return Err(e) - } - }; - {$data:expr, $func:expr, $($funcs:expr),+} => { - parser_selector_simple! {$data, $func}; - parser_selector_simple! {$data, $($funcs),*}; - }; -} - -#[macro_export] -macro_rules! parser_opcode { - ($data:expr, $opcode:expr) => { - if $data[0] != $opcode { - return Err(AmlError::AmlInvalidOpCode); - } - }; - ($data:expr, $opcode:expr, $alternate_opcode:expr) => { - if $data[0] != $opcode && $data[0] != $alternate_opcode { - return Err(AmlError::AmlInvalidOpCode); - } - }; -} - -#[macro_export] -macro_rules! parser_opcode_extended { - ($data:expr, $opcode:expr) => { - if $data[0] != 0x5B || $data[1] != $opcode { - return Err(AmlError::AmlInvalidOpCode); - } - }; -} diff --git a/src/acpi/aml/pkglength.rs b/src/acpi/aml/pkglength.rs deleted file mode 100644 index 7b511f9..0000000 --- a/src/acpi/aml/pkglength.rs +++ /dev/null @@ -1,25 +0,0 @@ -use super::AmlError; - -pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlError> { - 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(AmlError::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; - } - - Ok((pkg_len, count_bytes + 1)) -} diff --git a/src/acpi/aml/termlist.rs b/src/acpi/aml/termlist.rs deleted file mode 100644 index cd8e103..0000000 --- a/src/acpi/aml/termlist.rs +++ /dev/null @@ -1,174 +0,0 @@ -use alloc::vec::Vec; - -use super::AmlError; -use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState }; -use super::namespace::{AmlValue, get_namespace_string}; -use super::namespacemodifier::parse_namespace_modifier; -use super::namedobj::parse_named_obj; -use super::dataobj::{parse_data_obj, parse_arg_obj, parse_local_obj}; -use super::type1opcode::parse_type1_opcode; -use super::type2opcode::parse_type2_opcode; -use super::namestring::parse_name_string; - -pub fn parse_term_list(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let mut current_offset: usize = 0; - - while current_offset < data.len() { - let res = parse_term_obj(&data[current_offset..], ctx)?; - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) - } - - current_offset += res.len; - } - - Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) -} - -pub fn parse_term_arg(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_local_obj, - parse_data_obj, - parse_arg_obj, - parse_type2_opcode - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_object_list(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let mut current_offset: usize = 0; - - while current_offset < data.len() { - let res = parse_object(&data[current_offset..], ctx)?; - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) - } - - current_offset += res.len; - } - - Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) -} - -fn parse_object(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_namespace_modifier, - parse_named_obj - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_method_invocation(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let name = parse_name_string(data, ctx)?; - let method = ctx.get(name.val.clone())?; - - let method = match method { - AmlValue::None => return Err(AmlError::AmlDeferredLoad), - _ => method.get_as_method()? - }; - - let mut cur = 0; - let mut params: Vec = vec!(); - - let mut current_offset = name.len; - - while cur < method.arg_count { - let res = parse_term_arg(&data[current_offset..], ctx)?; - - current_offset += res.len; - cur += 1; - - params.push(res.val); - } - - Ok(AmlParseType { - val: method.execute(get_namespace_string(ctx.scope.clone(), name.val)?, params), - len: current_offset - }) -} - -fn parse_term_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_namespace_modifier, - parse_named_obj, - parse_type1_opcode, - parse_type2_opcode - }; - - Err(AmlError::AmlInvalidOpCode) -} diff --git a/src/acpi/aml/type1opcode.rs b/src/acpi/aml/type1opcode.rs deleted file mode 100644 index 28b86ca..0000000 --- a/src/acpi/aml/type1opcode.rs +++ /dev/null @@ -1,472 +0,0 @@ -use super::AmlError; -use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; -use super::namespace::AmlValue; -use super::pkglength::parse_pkg_length; -use super::termlist::{parse_term_arg, parse_term_list}; -use super::namestring::{parse_name_string, parse_super_name}; - -use crate::time::monotonic; - -use crate::acpi::{Sdt, load_table, get_sdt_signature}; -use super::{parse_aml_table, is_aml_table}; - -pub fn parse_type1_opcode(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_def_break, - parse_def_breakpoint, - parse_def_continue, - parse_def_noop, - 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(AmlError::AmlInvalidOpCode) -} - -fn parse_def_break(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA5); - ctx.state = ExecutionState::BREAK; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 as usize - }) -} - -fn parse_def_breakpoint(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xCC); - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 as usize - }) -} - -fn parse_def_continue(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x9F); - ctx.state = ExecutionState::CONTINUE; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 as usize - }) -} - -fn parse_def_noop(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA3); - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 as usize - }) -} - -fn parse_def_fatal(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x32); - - let fatal_type = data[2]; - let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8); - let fatal_arg = parse_term_arg(&data[5..], ctx)?; - - Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val)) -} - -fn parse_def_load(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x20); - - let name = parse_name_string(&data[2..], ctx)?; - let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?; - - let tbl = ctx.get(name.val)?.get_as_buffer()?; - let sdt = unsafe { &*(tbl.as_ptr() as *const Sdt) }; - - if is_aml_table(sdt) { - load_table(get_sdt_signature(sdt)); - let delta = parse_aml_table(sdt)?; - let _ = ctx.modify(ddb_handle_object.val, AmlValue::DDBHandle((delta, get_sdt_signature(sdt)))); - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + ddb_handle_object.len - }) - } else { - Err(AmlError::AmlValueError) - } -} - -fn parse_def_notify(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x86); - - let object = parse_super_name(&data[1..], ctx)?; - let value = parse_term_arg(&data[1 + object.len..], ctx)?; - - let number = value.val.get_as_integer()? as u8; - - match ctx.get(object.val)? { - AmlValue::Device(d) => { - if let Some(methods) = d.notify_methods.get(&number) { - for method in methods { - method(); - } - } - }, - AmlValue::Processor(d) => { - if let Some(methods) = d.notify_methods.get(&number) { - for method in methods { - method(); - } - } - }, - AmlValue::ThermalZone(d) => { - if let Some(methods) = d.notify_methods.get(&number) { - for method in methods { - method(); - } - } - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + object.len + value.len - }) -} - -fn parse_def_release(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x27); - - let obj = parse_super_name(&data[2..], ctx)?; - let _ = ctx.release_mutex(obj.val); - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + obj.len - }) -} - -fn parse_def_reset(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x26); - - let object = parse_super_name(&data[2..], ctx)?; - ctx.get(object.val.clone())?.get_as_event()?; - - let _ = ctx.modify(object.val.clone(), AmlValue::Event(0)); - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + object.len - }) -} - -fn parse_def_signal(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x24); - let object = parse_super_name(&data[2..], ctx)?; - - ctx.signal_event(object.val)?; - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + object.len - }) -} - -fn parse_def_sleep(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x22); - - let time = parse_term_arg(&data[2..], ctx)?; - let timeout = time.val.get_as_integer()?; - - let (seconds, nanoseconds) = monotonic(); - let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); - - loop { - let (seconds, nanoseconds) = monotonic(); - let current_time_ns = nanoseconds + (seconds * 1_000_000_000); - - if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 { - break; - } - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + time.len - }) -} - -fn parse_def_stall(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x21); - - let time = parse_term_arg(&data[2..], ctx)?; - let timeout = time.val.get_as_integer()?; - - let (seconds, nanoseconds) = monotonic(); - let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); - - loop { - let (seconds, nanoseconds) = monotonic(); - let current_time_ns = nanoseconds + (seconds * 1_000_000_000); - - if current_time_ns - starting_time_ns > timeout as u64 * 1000 { - break; - } - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + time.len - }) -} - -fn parse_def_unload(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x2A); - - let object = parse_super_name(&data[2..], ctx)?; - - let delta = ctx.get(object.val)?.get_as_ddb_handle()?; - let mut namespace = ctx.prelock(); - - if let Some(ref mut ns) = *namespace { - for o in delta.0 { - ns.remove(&o); - } - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + object.len - }) -} - -fn parse_def_if_else(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA0); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let if_condition = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?; - - let (else_length, else_length_len) = if data.len() > 1 + pkg_length && data[1 + pkg_length] == 0xA1 { - parse_pkg_length(&data[2 + pkg_length..])? - } else { - (0 as usize, 0 as usize) - }; - - if if_condition.val.get_as_integer()? > 0 { - parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?; - } else if else_length > 0 { - parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?; - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + pkg_length + if else_length > 0 { 1 + else_length } else { 0 } - }) -} - -fn parse_def_while(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA2); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - - loop { - let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; - if predicate.val.get_as_integer()? == 0 { - break; - } - - parse_term_list(&data[1 + pkg_length_len + predicate.len .. 1 + pkg_length], ctx)?; - - match ctx.state { - ExecutionState::EXECUTING => (), - ExecutionState::BREAK => { - ctx.state = ExecutionState::EXECUTING; - break; - }, - ExecutionState::CONTINUE => ctx.state = ExecutionState::EXECUTING, - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + pkg_length - }) -} - -fn parse_def_return(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA4); - - let arg_object = parse_term_arg(&data[1..], ctx)?; - ctx.state = ExecutionState::RETURN(arg_object.val); - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + arg_object.len - }) -} diff --git a/src/acpi/aml/type2opcode.rs b/src/acpi/aml/type2opcode.rs deleted file mode 100644 index 5c37652..0000000 --- a/src/acpi/aml/type2opcode.rs +++ /dev/null @@ -1,1779 +0,0 @@ -use alloc::boxed::Box; -use alloc::string::String; -use alloc::vec::Vec; - -use super::{AmlError, parse_aml_with_scope}; -use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; -use super::namespace::{AmlValue, ObjectReference}; -use super::pkglength::parse_pkg_length; -use super::termlist::{parse_term_arg, parse_method_invocation}; -use super::namestring::{parse_super_name, parse_target, parse_name_string, parse_simple_name}; -use super::dataobj::parse_data_ref_obj; - -use crate::time::monotonic; -use crate::acpi::SDT_POINTERS; - -#[derive(Debug, Clone)] -pub enum MatchOpcode { - MTR, - MEQ, - MLE, - MLT, - MGE, - MGT -} - -pub fn parse_type2_opcode(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - 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, - parse_def_buffer, - parse_def_package, - parse_def_var_package, - parse_def_object_type, - parse_def_deref_of, - parse_def_ref_of, - parse_def_index, - parse_method_invocation - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_type6_opcode(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_def_deref_of, - parse_def_ref_of, - parse_def_index, - parse_method_invocation - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_def_object_type(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8E); - parser_selector! { - data, ctx, - parse_super_name, - parse_def_ref_of, - parse_def_deref_of, - parse_def_index - } - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_def_package(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Handle deferred loads in here - parser_opcode!(data, 0x12); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let numelements = data[1 + pkg_length_len] as usize; - let mut elements = parse_package_elements_list(&data[2 + pkg_length_len .. 1 + pkg_length], ctx)?.val.get_as_package()?; - - if elements.len() > numelements { - elements = elements[0 .. numelements].to_vec(); - } else if numelements > elements.len() { - for _ in 0..numelements - elements.len() { - elements.push(AmlValue::Uninitialized); - } - } - - Ok(AmlParseType { - val: AmlValue::Package(elements), - len: 1 + pkg_length - }) -} - -pub fn parse_def_var_package(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Handle deferred loads in here - parser_opcode!(data, 0x13); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let num_elements = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?; - let mut elements = parse_package_elements_list(&data[1 + pkg_length_len + num_elements.len .. - 1 + pkg_length], ctx)?.val.get_as_package()?; - - let numelements = num_elements.val.get_as_integer()? as usize; - - if elements.len() > numelements { - elements = elements[0 .. numelements].to_vec(); - } else if numelements > elements.len() { - for _ in 0..numelements - elements.len() { - elements.push(AmlValue::Uninitialized); - } - } - - Ok(AmlParseType { - val: AmlValue::Package(elements), - len: 1 + pkg_length - }) -} - -fn parse_package_elements_list(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let mut current_offset: usize = 0; - let mut elements: Vec = vec!(); - - while current_offset < data.len() { - let dro = if let Ok(e) = parse_data_ref_obj(&data[current_offset..], ctx) { - e - } else { - let d = parse_name_string(&data[current_offset..], ctx)?; - AmlParseType { - val: AmlValue::ObjectReference(ObjectReference::Object(d.val.get_as_string()?)), - len: d.len - } - }; - - elements.push(dro.val); - current_offset += dro.len; - } - - Ok(AmlParseType { - val: AmlValue::Package(elements), - len: data.len() - }) -} - -pub fn parse_def_buffer(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x11); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let buffer_size = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; - let mut byte_list = data[1 + pkg_length_len + buffer_size.len .. 1 + pkg_length].to_vec().clone(); - - byte_list.truncate(buffer_size.val.get_as_integer()? as usize); - - Ok(AmlParseType { - val: AmlValue::Buffer(byte_list), - len: 1 + pkg_length - }) -} - -fn parse_def_ref_of(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x71); - - let obj = parse_super_name(&data[1..], ctx)?; - let res = match obj.val { - AmlValue::String(ref s) => { - match ctx.get(AmlValue::String(s.clone()))? { - AmlValue::None => return Err(AmlError::AmlValueError), - _ => ObjectReference::Object(s.clone()) - } - }, - AmlValue::ObjectReference(ref o) => o.clone(), - _ => return Err(AmlError::AmlValueError) - }; - - Ok(AmlParseType { - val: AmlValue::ObjectReference(res), - len: 1 + obj.len - }) -} - -fn parse_def_deref_of(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x83); - - let obj = parse_term_arg(&data[1..], ctx)?; - let res = ctx.get(obj.val)?; - - match res { - AmlValue::None => Err(AmlError::AmlValueError), - _ => Ok(AmlParseType { - val: res, - len: 1 + obj.len - }) - } -} - -fn parse_def_acquire(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x23); - - let obj = parse_super_name(&data[1..], ctx)?; - let timeout = (data[2 + obj.len] as u16) + ((data[3 + obj.len] as u16) << 8); - - let (seconds, nanoseconds) = monotonic(); - let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); - - loop { - match ctx.acquire_mutex(obj.val.clone()) { - Err(e) => return Err(e), - Ok(b) => if b { - return Ok(AmlParseType { - val: AmlValue::Integer(0), - len: 4 + obj.len - }); - } else if timeout == 0xFFFF { - // TODO: Brief sleep here - } else { - let (seconds, nanoseconds) = monotonic(); - let current_time_ns = nanoseconds + (seconds * 1_000_000_000); - - if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 { - return Ok(AmlParseType { - val: AmlValue::Integer(1), - len: 4 + obj.len - }); - } - } - } - } -} - -fn parse_def_increment(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x75); - - let obj = parse_super_name(&data[1..], ctx)?; - - let _namespace = ctx.prelock(); - let value = AmlValue::Integer(ctx.get(obj.val.clone())?.get_as_integer()? + 1); - let _ = ctx.modify(obj.val, value.clone()); - - Ok(AmlParseType { - val: value, - len: 1 + obj.len - }) -} - -fn parse_def_index(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x88); - - let obj = parse_term_arg(&data[1..], ctx)?; - let idx = parse_term_arg(&data[1 + obj.len..], ctx)?; - let target = parse_target(&data[1 + obj.len + idx.len..], ctx)?; - - let reference = AmlValue::ObjectReference(ObjectReference::Index(Box::new(obj.val), Box::new(idx.val))); - let _ = ctx.modify(target.val, reference.clone()); - - Ok(AmlParseType { - val: reference, - len: 1 + obj.len + idx.len + target.len - }) -} - -fn parse_def_land(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x90); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer()? > 0 && rhs.val.get_as_integer()? > 0 { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_lequal(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x93); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer()? == rhs.val.get_as_integer()? { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_lgreater(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x94); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer()? > rhs.val.get_as_integer()? { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_lless(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x95); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer()? < rhs.val.get_as_integer()? { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_lnot(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x92); - - let operand = parse_term_arg(&data[1..], ctx)?; - let result = if operand.val.get_as_integer()? == 0 { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + operand.len - }) -} - -fn parse_def_lor(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x91); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer()? > 0 || rhs.val.get_as_integer()? > 0 { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_to_hex_string(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x98); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let res = match operand.val { - AmlValue::Integer(_) => { - let result: String = format!("{:X}", operand.val.get_as_integer()?); - AmlValue::String(result) - }, - AmlValue::String(s) => AmlValue::String(s), - AmlValue::Buffer(_) => { - let mut string: String = String::new(); - - for b in operand.val.get_as_buffer()? { - string.push_str(&format!("{:X}", b)); - } - - AmlValue::String(string) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let _ = ctx.modify(target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_buffer(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x96); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let res = AmlValue::Buffer(operand.val.get_as_buffer()?); - let _ = ctx.modify(target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_bcd(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x29); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let mut i = operand.val.get_as_integer()?; - let mut result = 0; - - while i != 0 { - result <<= 4; - result += i % 10; - i /= 10; - } - - let result = AmlValue::Integer(result); - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_decimal_string(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x97); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - let res = match operand.val { - AmlValue::Integer(_) => { - let result: String = format!("{}", operand.val.get_as_integer()?); - AmlValue::String(result) - }, - AmlValue::String(s) => AmlValue::String(s), - AmlValue::Buffer(_) => { - let mut string: String = String::new(); - - for b in operand.val.get_as_buffer()? { - string.push_str(&format!("{}", b)); - } - - AmlValue::String(string) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let _ = ctx.modify(target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_integer(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x99); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let res = AmlValue::Integer(operand.val.get_as_integer()?); - - let _ = ctx.modify(target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_string(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x9C); - - let operand = parse_term_arg(&data[1..], ctx)?; - let length = parse_term_arg(&data[1 + operand.len..], ctx)?; - let target = parse_target(&data[1 + operand.len + length.len..], ctx)?; - - let buf = operand.val.get_as_buffer()?; - let mut string = match String::from_utf8(buf) { - Ok(s) => s, - Err(_) => return Err(AmlError::AmlValueError) - }; - - string.truncate(length.val.get_as_integer()? as usize); - let res = AmlValue::String(string); - - let _ = ctx.modify(target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + length.len + target.len - }) -} - -fn parse_def_subtract(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x74); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer()? - rhs.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_size_of(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x87); - - let name = parse_super_name(&data[1..], ctx)?; - let obj = ctx.get(name.val)?; - - let res = match obj { - AmlValue::Buffer(ref v) => v.len(), - AmlValue::String(ref s) => s.len(), - AmlValue::Package(ref p) => p.len(), - _ => return Err(AmlError::AmlValueError) - }; - - Ok(AmlParseType { - val: AmlValue::Integer(res as u64), - len: 1 + name.len - }) -} - -fn parse_def_store(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x70); - - let operand = parse_term_arg(&data[1..], ctx)?; - let target = parse_super_name(&data[1 + operand.len..], ctx)?; - - let _ = ctx.modify(target.val.clone(), operand.val); - - Ok(AmlParseType { - val: target.val, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_or(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7D); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer()? | rhs.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_shift_left(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x79); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer()? >> rhs.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_shift_right(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7A); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer()? << rhs.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_add(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x72); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer()? + rhs.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_and(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7B); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer()? & rhs.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_xor(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7F); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer()? ^ rhs.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_concat_res(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x84); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let mut buf1 = lhs.val.get_as_buffer()?.clone(); - let mut buf2 = rhs.val.get_as_buffer()?.clone(); - - if buf1.len() == 1 || buf2.len() == 1 { - return Err(AmlError::AmlValueError); - } - - if buf1.len() >= 2 && buf1[buf1.len() - 2] == 0x79 { - buf1 = buf1[0..buf1.len() - 2].to_vec(); - } - - if buf2.len() >= 2 && buf2[buf2.len() - 2] == 0x79 { - buf2 = buf2[0..buf2.len() - 2].to_vec(); - } - - buf1.append(&mut buf2); - buf1.push(0x79); - - let mut checksum: u8 = 0; - let loopbuf = buf1.clone(); - for b in loopbuf { - checksum += b; - } - - checksum = (!checksum) + 1; - buf1.push(checksum); - - let res = AmlValue::Buffer(buf1); - ctx.modify(target.val, res.clone())?; - - Ok(AmlParseType { - val: res, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_wait(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x25); - - let obj = parse_super_name(&data[2..], ctx)?; - let timeout_obj = parse_term_arg(&data[2 + obj.len..], ctx)?; - - let timeout = timeout_obj.val.get_as_integer()?; - - let (seconds, nanoseconds) = monotonic(); - let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); - - loop { - match ctx.wait_for_event(obj.val.clone()) { - Err(e) => return Err(e), - Ok(b) => if b { - return Ok(AmlParseType { - val: AmlValue::Integer(0), - len: 2 + obj.len + timeout_obj.len - }) - } else if timeout >= 0xFFFF { - // TODO: Brief sleep here - } else { - let (seconds, nanoseconds) = monotonic(); - let current_time_ns = nanoseconds + (seconds * 1_000_000_000); - - if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 { - return Ok(AmlParseType { - val: AmlValue::Integer(1), - len: 2 + obj.len + timeout_obj.len - }); - } - } - } - } -} - -fn parse_def_cond_ref_of(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x12); - - let obj = parse_super_name(&data[2..], ctx)?; - let target = parse_target(&data[2 + obj.len..], ctx)?; - - let res = match obj.val { - AmlValue::String(ref s) => { - match ctx.get(AmlValue::String(s.clone()))? { - AmlValue::None => return Ok(AmlParseType { - val: AmlValue::Integer(0), - len: 1 + obj.len + target.len - }), - _ => ObjectReference::Object(s.clone()) - } - }, - AmlValue::ObjectReference(ref o) => o.clone(), - _ => return Err(AmlError::AmlValueError) - }; - - let _ = ctx.modify(target.val, AmlValue::ObjectReference(res)); - - Ok(AmlParseType { - val: AmlValue::Integer(1), - len: 1 + obj.len + target.len - }) -} - -fn parse_def_copy_object(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Compute the result - // TODO: Store the result - parser_opcode!(data, 0x9D); - - let source = parse_term_arg(&data[1..], ctx)?; - let destination = parse_simple_name(&data[1 + source.len..], ctx)?; - - ctx.copy(destination.val, source.val.clone())?; - - Ok(AmlParseType { - val: source.val, - len: 1 + source.len + destination.len - }) -} - -fn parse_def_concat(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x73); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = match lhs.val { - AmlValue::Integer(_i) => { - let j = AmlValue::Integer(rhs.val.get_as_integer()?); - - let mut first = lhs.val.get_as_buffer()?.clone(); - let mut second = j.get_as_buffer()?.clone(); - - first.append(&mut second); - - AmlValue::Buffer(first) - }, - AmlValue::String(s) => { - let t = if let Ok(t) = rhs.val.get_as_string() { - t - } else { - rhs.val.get_type_string() - }; - - AmlValue::String(format!("{}{}", s, t)) - }, - AmlValue::Buffer(b) => { - let mut b = b.clone(); - let mut c = if let Ok(c) = rhs.val.get_as_buffer() { - c.clone() - } else { - AmlValue::String(rhs.val.get_type_string()).get_as_buffer()?.clone() - }; - - b.append(&mut c); - - AmlValue::Buffer(b) - }, - _ => { - let first = lhs.val.get_type_string(); - let second = if let Ok(second) = rhs.val.get_as_string() { - second - } else { - rhs.val.get_type_string() - }; - - AmlValue::String(format!("{}{}", first, second)) - } - }; - - ctx.modify(target.val, result.clone())?; - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_decrement(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x76); - - let obj = parse_super_name(&data[1..], ctx)?; - - let _namespace = ctx.prelock(); - let value = AmlValue::Integer(ctx.get(obj.val.clone())?.get_as_integer()? - 1); - let _ = ctx.modify(obj.val, value.clone()); - - Ok(AmlParseType { - val: value, - len: 1 + obj.len - }) -} - -fn parse_def_divide(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x78); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target_remainder = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let target_quotient = parse_target(&data[1 + lhs.len + rhs.len + target_remainder.len..], ctx)?; - - let numerator = lhs.val.get_as_integer()?; - let denominator = rhs.val.get_as_integer()?; - - let remainder = numerator % denominator; - let quotient = (numerator - remainder) / denominator; - - let _ = ctx.modify(target_remainder.val, AmlValue::Integer(remainder)); - let _ = ctx.modify(target_quotient.val, AmlValue::Integer(quotient)); - - Ok(AmlParseType { - val: AmlValue::Integer(quotient), - len: 1 + lhs.len + rhs.len + target_remainder.len + target_quotient.len - }) -} - -fn parse_def_find_set_left_bit(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x81); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let mut first_bit = 32; - let mut test = operand.val.get_as_integer()?; - - while first_bit > 0{ - if test & 0x8000_0000_0000_0000 > 0 { - break; - } - - test <<= 1; - first_bit -= 1; - } - - let result = AmlValue::Integer(first_bit); - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_find_set_right_bit(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x82); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let mut first_bit = 1; - let mut test = operand.val.get_as_integer()?; - - while first_bit <= 32 { - if test & 1 > 0 { - break; - } - - test >>= 1; - first_bit += 1; - } - - if first_bit == 33 { - first_bit = 0; - } - - let result = AmlValue::Integer(first_bit); - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_load_table(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Clean up - parser_opcode_extended!(data, 0x1F); - - let signature = parse_term_arg(&data[2..], ctx)?; - let oem_id = parse_term_arg(&data[2 + signature.len..], ctx)?; - let oem_table_id = parse_term_arg(&data[2 + signature.len + oem_id.len..], ctx)?; - let root_path = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len..], ctx)?; - let parameter_path = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len..], ctx)?; - let parameter_data = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len + parameter_path.len..], ctx)?; - - if let Some(ref ptrs) = *(SDT_POINTERS.read()) { - let sig_str = unsafe { - let sig = *(signature.val.get_as_string()?.as_bytes().as_ptr() as *const [u8; 4]); - String::from_utf8(sig.to_vec()).expect("Error converting signature to string") - }; - let oem_str = unsafe { - *(oem_id.val.get_as_string()?.as_bytes().as_ptr() as *const [u8; 6]) - }; - let oem_table_str = unsafe { - *(oem_table_id.val.get_as_string()?.as_bytes().as_ptr() as *const [u8; 8]) - }; - - let sdt_signature = (sig_str, oem_str, oem_table_str); - - let sdt = ptrs.get(&sdt_signature); - - if let Some(sdt) = sdt { - let hdl = parse_aml_with_scope(sdt, root_path.val.get_as_string()?)?; - let _ = ctx.modify(parameter_path.val, parameter_data.val); - - return Ok(AmlParseType { - val: AmlValue::DDBHandle((hdl, sdt_signature)), - len: 2 + signature.len + oem_id.len + oem_table_id.len + root_path.len + parameter_path.len + parameter_data.len - }); - } - } - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(0), - len: 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], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x28); - - let search_pkg = parse_term_arg(&data[1..], ctx)?; - - 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(AmlError::AmlParseError("DefMatch - Invalid Opcode")) - }; - let first_operand = parse_term_arg(&data[2 + search_pkg.len..], ctx)?; - - 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(AmlError::AmlParseError("DefMatch - Invalid Opcode")) - }; - let second_operand = parse_term_arg(&data[3 + search_pkg.len + first_operand.len..], ctx)?; - - let start_index = parse_term_arg(&data[3 + search_pkg.len + first_operand.len + second_operand.len..], ctx)?; - - let pkg = search_pkg.val.get_as_package()?; - let mut idx = start_index.val.get_as_integer()? as usize; - - match first_operand.val { - AmlValue::Integer(i) => { - let j = second_operand.val.get_as_integer()?; - - while idx < pkg.len() { - let val = if let Ok(v) = pkg[idx].get_as_integer() { v } else { idx += 1; continue; }; - idx += 1; - - match first_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != i { continue }, - MatchOpcode::MLE => if val > i { continue }, - MatchOpcode::MLT => if val >= i { continue }, - MatchOpcode::MGE => if val < i { continue }, - MatchOpcode::MGT => if val <= i { continue } - } - - match second_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != j { continue }, - MatchOpcode::MLE => if val > j { continue }, - MatchOpcode::MLT => if val >= j { continue }, - MatchOpcode::MGE => if val < j { continue }, - MatchOpcode::MGT => if val <= j { continue } - } - - return Ok(AmlParseType { - val: AmlValue::Integer(idx as u64), - len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len - }) - } - }, - AmlValue::String(i) => { - let j = second_operand.val.get_as_string()?; - - while idx < pkg.len() { - let val = if let Ok(v) = pkg[idx].get_as_string() { v } else { idx += 1; continue; }; - idx += 1; - - match first_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != i { continue }, - MatchOpcode::MLE => if val > i { continue }, - MatchOpcode::MLT => if val >= i { continue }, - MatchOpcode::MGE => if val < i { continue }, - MatchOpcode::MGT => if val <= i { continue } - } - - match second_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != j { continue }, - MatchOpcode::MLE => if val > j { continue }, - MatchOpcode::MLT => if val >= j { continue }, - MatchOpcode::MGE => if val < j { continue }, - MatchOpcode::MGT => if val <= j { continue } - } - - return Ok(AmlParseType { - val: AmlValue::Integer(idx as u64), - len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len - }) - } - }, - _ => { - let i = first_operand.val.get_as_buffer()?; - let j = second_operand.val.get_as_buffer()?; - - while idx < pkg.len() { - let val = if let Ok(v) = pkg[idx].get_as_buffer() { v } else { idx += 1; continue; }; - idx += 1; - - match first_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != i { continue }, - MatchOpcode::MLE => if val > i { continue }, - MatchOpcode::MLT => if val >= i { continue }, - MatchOpcode::MGE => if val < i { continue }, - MatchOpcode::MGT => if val <= i { continue } - } - - match second_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != j { continue }, - MatchOpcode::MLE => if val > j { continue }, - MatchOpcode::MLT => if val >= j { continue }, - MatchOpcode::MGE => if val < j { continue }, - MatchOpcode::MGT => if val <= j { continue } - } - - return Ok(AmlParseType { - val: AmlValue::Integer(idx as u64), - len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len - }) - } - } - } - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(0xFFFF_FFFF_FFFF_FFFF), - len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len - }) -} - -fn parse_def_from_bcd(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x28); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let mut i = operand.val.get_as_integer()?; - let mut result = 0; - - while i != 0 { - if i & 0x0F > 10 { - return Err(AmlError::AmlValueError); - } - - result *= 10; - result += i & 0x0F; - i >>= 4; - } - - let result = AmlValue::Integer(result); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 2 + operand.len + target.len - }) -} - -fn parse_def_mid(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x9E); - - let source = parse_term_arg(&data[1..], ctx)?; - let index = parse_term_arg(&data[1 + source.len..], ctx)?; - let length = parse_term_arg(&data[1 + source.len + index.len..], ctx)?; - let target = parse_target(&data[1 + source.len + index.len + length.len..], ctx)?; - - let idx = index.val.get_as_integer()? as usize; - let mut len = length.val.get_as_integer()? as usize; - - let result = match source.val { - AmlValue::String(s) => { - if idx > s.len() { - AmlValue::String(String::new()) - } else { - let mut res = s.clone().split_off(idx); - - if len < res.len() { - res.split_off(len).clear(); - } - - AmlValue::String(res) - } - }, - _ => { - // If it isn't a string already, treat it as a buffer. Must perform that check first, - // as Mid can operate on both strings and buffers, but a string can be cast as a buffer - // implicitly. - // Additionally, any type that can be converted to a buffer can also be converted to a - // string, so no information is lost - let b = source.val.get_as_buffer()?; - - if idx > b.len() { - AmlValue::Buffer(vec!()) - } else { - if idx + len > b.len() { - len = b.len() - idx; - } - - AmlValue::Buffer(b[idx .. idx + len].to_vec()) - } - } - }; - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + source.len + index.len + length.len + target.len - }) -} - -fn parse_def_mod(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x85); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - if rhs.val.get_as_integer()? == 0 { - return Err(AmlError::AmlValueError); - } - - let result = AmlValue::Integer(lhs.val.get_as_integer()? % rhs.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_multiply(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Handle overflow - parser_opcode!(data, 0x77); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer()? * rhs.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_nand(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7C); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(!(lhs.val.get_as_integer()? & rhs.val.get_as_integer()?)); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_nor(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7E); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(!(lhs.val.get_as_integer()? | rhs.val.get_as_integer()?)); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_not(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x80); - - let operand = parse_term_arg(&data[1..], ctx)?; - let target = parse_target(&data[1 + operand.len..], ctx)?; - - let result = AmlValue::Integer(!operand.val.get_as_integer()?); - - let _ = ctx.modify(target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_timer(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x33); - - let (seconds, nanoseconds) = monotonic(); - let monotonic_ns = nanoseconds + (seconds * 1_000_000_000); - - Ok(AmlParseType { - val: AmlValue::Integer(monotonic_ns), - len: 2 as usize - }) -} diff --git a/src/acpi/fadt.rs b/src/acpi/fadt.rs index 4ee13e9..e69de29 100644 --- a/src/acpi/fadt.rs +++ b/src/acpi/fadt.rs @@ -1,124 +0,0 @@ -use core::{mem, ptr}; - -use super::sdt::Sdt; -use super::{ACPI_TABLE, SDT_POINTERS, get_sdt, find_sdt, get_sdt_signature, load_table}; - -use crate::paging::ActivePageTable; - -#[repr(packed)] -#[derive(Clone, Copy, Debug)] -pub struct Fadt { - pub header: Sdt, - pub firmware_ctrl: u32, - pub dsdt: u32, - - // field used in ACPI 1.0; no longer in use, for compatibility only - reserved: u8, - - pub preferred_power_managament: u8, - pub sci_interrupt: u16, - pub smi_command_port: u32, - pub acpi_enable: u8, - pub acpi_disable: u8, - pub s4_bios_req: u8, - pub pstate_control: u8, - pub pm1a_event_block: u32, - pub pm1b_event_block: u32, - pub pm1a_control_block: u32, - pub pm1b_control_block: u32, - pub pm2_control_block: u32, - pub pm_timer_block: u32, - pub gpe0_block: u32, - pub gpe1_block: u32, - pub pm1_event_length: u8, - pub pm1_control_length: u8, - pub pm2_control_length: u8, - pub pm_timer_length: u8, - pub gpe0_ength: u8, - pub gpe1_length: u8, - pub gpe1_base: u8, - pub c_state_control: u8, - pub worst_c2_latency: u16, - pub worst_c3_latency: u16, - pub flush_size: u16, - pub flush_stride: u16, - pub duty_offset: u8, - pub duty_width: u8, - pub day_alarm: u8, - pub month_alarm: u8, - pub century: u8, - - // reserved in ACPI 1.0; used since ACPI 2.0+ - pub boot_architecture_flags: u16, - - reserved2: u8, - pub flags: u32, -} - -/* ACPI 2 structure -#[repr(packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct GenericAddressStructure { - address_space: u8, - bit_width: u8, - bit_offset: u8, - access_size: u8, - address: u64, -} - -{ - // 12 byte structure; see below for details - pub reset_reg: GenericAddressStructure, - - pub reset_value: u8, - reserved3: [u8; 3], - - // 64bit pointers - Available on ACPI 2.0+ - pub x_firmware_control: u64, - pub x_dsdt: u64, - - pub x_pm1a_event_block: GenericAddressStructure, - pub x_pm1b_event_block: GenericAddressStructure, - pub x_pm1a_control_block: GenericAddressStructure, - pub x_pm1b_control_block: GenericAddressStructure, - pub x_pm2_control_block: GenericAddressStructure, - pub x_pm_timer_block: GenericAddressStructure, - pub x_gpe0_block: GenericAddressStructure, - pub x_gpe1_block: GenericAddressStructure, -} -*/ - -impl Fadt { - pub fn new(sdt: &'static Sdt) -> Option { - if &sdt.signature == b"FACP" && sdt.length as usize >= mem::size_of::() { - Some(unsafe { ptr::read((sdt as *const Sdt) as *const Fadt) }) - } else { - None - } - } - - pub fn init(active_table: &mut ActivePageTable) { - let fadt_sdt = find_sdt("FACP"); - let fadt = if fadt_sdt.len() == 1 { - load_table(get_sdt_signature(fadt_sdt[0])); - Fadt::new(fadt_sdt[0]) - } else { - println!("Unable to find FADT"); - return; - }; - - if let Some(fadt) = fadt { - println!(" FACP: {:X}", {fadt.dsdt}); - - let dsdt_sdt = get_sdt(fadt.dsdt as usize, active_table); - - let signature = get_sdt_signature(dsdt_sdt); - if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) { - ptrs.insert(signature, dsdt_sdt); - } - - let mut fadt_t = ACPI_TABLE.fadt.write(); - *fadt_t = Some(fadt); - } - } -} diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 13b6743..3d6adeb 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -6,18 +6,13 @@ use alloc::string::String; use alloc::vec::Vec; use alloc::boxed::Box; -use syscall::io::{Io, Pio}; - -use spin::RwLock; - -use crate::stop::kstop; +use spin::{Once, RwLock}; use crate::log::info; use crate::memory::Frame; use crate::paging::{ActivePageTable, Page, PageFlags, PhysicalAddress, VirtualAddress}; use self::dmar::Dmar; -use self::fadt::Fadt; use self::madt::Madt; use self::rsdt::Rsdt; use self::sdt::Sdt; @@ -26,8 +21,6 @@ use self::hpet::Hpet; use self::rxsdt::Rxsdt; use self::rsdp::RSDP; -use self::aml::{parse_aml_table, AmlError, AmlValue}; - pub mod hpet; mod dmar; mod fadt; @@ -35,7 +28,6 @@ pub mod madt; mod rsdt; pub mod sdt; mod xsdt; -pub mod aml; mod rxsdt; mod rsdp; @@ -67,48 +59,20 @@ pub fn get_sdt(sdt_address: usize, active_table: &mut ActivePageTable) -> &'stat sdt } -fn init_aml_table(sdt: &'static Sdt) { - match parse_aml_table(sdt) { - Ok(_) => println!(": Parsed"), - Err(AmlError::AmlParseError(e)) => println!(": {}", e), - Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"), - Err(AmlError::AmlValueError) => println!(": Type constraints or value bounds not met"), - Err(AmlError::AmlDeferredLoad) => println!(": Deferred load reached top level"), - Err(AmlError::AmlFatalError(_, _, _)) => { - println!(": Fatal error occurred"); - unsafe { kstop(); } - }, - Err(AmlError::AmlHardFatal) => { - println!(": Fatal error occurred"); - unsafe { kstop(); } +pub enum RxsdtEnum { + Rsdt(Rsdt), + Xsdt(Xsdt), +} +impl Rxsdt for RxsdtEnum { + fn iter(&self) -> Box> { + match self { + Self::Rsdt(rsdt) => ::iter(rsdt), + Self::Xsdt(xsdt) => ::iter(xsdt), } } } -fn init_namespace() { - { - let mut namespace = ACPI_TABLE.namespace.write(); - *namespace = Some(BTreeMap::new()); - } - - let dsdt = find_sdt("DSDT"); - if dsdt.len() == 1 { - print!(" DSDT"); - load_table(get_sdt_signature(dsdt[0])); - init_aml_table(dsdt[0]); - } else { - println!("Unable to find DSDT"); - return; - }; - - let ssdts = find_sdt("SSDT"); - - for ssdt in ssdts { - print!(" SSDT"); - load_table(get_sdt_signature(ssdt)); - init_aml_table(ssdt); - } -} +pub static RXSDT_ENUM: Once = Once::new(); /// Parse the ACPI tables to gather CPU, interrupt, and timer information pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: Option<(u64, u64)>) { @@ -132,10 +96,33 @@ pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: O } println!(":"); - let rxsdt: Box = if let Some(rsdt) = Rsdt::new(rxsdt) { - Box::new(rsdt) + let rxsdt = if let Some(rsdt) = Rsdt::new(rxsdt) { + let mut initialized = false; + + let rsdt = RXSDT_ENUM.call_once(|| { + initialized = true; + + RxsdtEnum::Rsdt(rsdt) + }); + + if !initialized { + log::error!("RXSDT_ENUM already initialized"); + } + + rsdt } else if let Some(xsdt) = Xsdt::new(rxsdt) { - Box::new(xsdt) + let mut initialized = false; + + let xsdt = RXSDT_ENUM.call_once(|| { + initialized = true; + + RxsdtEnum::Xsdt(xsdt) + }); + if !initialized { + log::error!("RXSDT_ENUM already initialized"); + } + + xsdt } else { println!("UNKNOWN RSDT OR XSDT SIGNATURE"); return; @@ -152,44 +139,14 @@ pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: O } } - Fadt::init(active_table); Madt::init(active_table); Dmar::init(active_table); Hpet::init(active_table); - init_namespace(); } else { println!("NO RSDP FOUND"); } } -pub fn set_global_s_state(state: u8) { - if state == 5 { - let fadt = ACPI_TABLE.fadt.read(); - - if let Some(ref fadt) = *fadt { - let port = fadt.pm1a_control_block as u16; - let mut val = 1 << 13; - - let namespace = ACPI_TABLE.namespace.read(); - - if let Some(ref namespace) = *namespace { - if let Some(s) = namespace.get("\\_S5") { - if let Ok(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); - } - } - } - } - } -} - pub type SdtSignature = (String, [u8; 6], [u8; 8]); pub static SDT_POINTERS: RwLock>> = RwLock::new(None); pub static SDT_ORDER: RwLock>> = RwLock::new(None); @@ -249,15 +206,11 @@ pub fn get_index_from_signature(signature: SdtSignature) -> Option { } pub struct Acpi { - pub fadt: RwLock>, - pub namespace: RwLock>>, pub hpet: RwLock>, pub next_ctx: RwLock, } pub static ACPI_TABLE: Acpi = Acpi { - fadt: RwLock::new(None), - namespace: RwLock::new(None), hpet: RwLock::new(None), next_ctx: RwLock::new(0), }; diff --git a/src/acpi/rsdt.rs b/src/acpi/rsdt.rs index c2eb8c9..750c464 100644 --- a/src/acpi/rsdt.rs +++ b/src/acpi/rsdt.rs @@ -1,3 +1,4 @@ +use core::convert::TryFrom; use core::mem; use alloc::boxed::Box; @@ -15,6 +16,14 @@ impl Rsdt { None } } + pub fn as_slice(&self) -> &[u8] { + let length = usize::try_from(self.0.length) + .expect("expected 32-bit length to fit within usize"); + + unsafe { + core::slice::from_raw_parts(self.0 as *const _ as *const u8, length) + } + } } impl Rxsdt for Rsdt { diff --git a/src/acpi/xsdt.rs b/src/acpi/xsdt.rs index 9f0d363..6dc69b6 100644 --- a/src/acpi/xsdt.rs +++ b/src/acpi/xsdt.rs @@ -1,3 +1,4 @@ +use core::convert::TryFrom; use core::mem; use alloc::boxed::Box; @@ -15,6 +16,14 @@ impl Xsdt { None } } + pub fn as_slice(&self) -> &[u8] { + let length = usize::try_from(self.0.length) + .expect("expected 32-bit length to fit within usize"); + + unsafe { + core::slice::from_raw_parts(self.0 as *const _ as *const u8, length) + } + } } impl Rxsdt for Xsdt { diff --git a/src/arch/x86_64/device/ioapic.rs b/src/arch/x86_64/device/ioapic.rs index 54ea18a..dfd405c 100644 --- a/src/arch/x86_64/device/ioapic.rs +++ b/src/arch/x86_64/device/ioapic.rs @@ -356,7 +356,12 @@ pub unsafe fn init(active_table: &mut ActivePageTable) { irq::set_irq_method(irq::IrqMethod::Apic); // tell the firmware that we're using APIC rather than the default 8259 PIC. - #[cfg(feature = "acpi")] + + // FIXME: With ACPI moved to userspace, we should instead allow userspace to check whether the + // IOAPIC has been initialized, and then subsequently let some ACPI driver call the AML from + // userspace. + + /*#[cfg(feature = "acpi")] { let method = { let namespace_guard = crate::acpi::ACPI_TABLE.namespace.read(); @@ -369,7 +374,7 @@ pub unsafe fn init(active_table: &mut ActivePageTable) { if let Some(m) = method { m.execute("\\_PIC".into(), vec!(crate::acpi::aml::AmlValue::Integer(1))); } - } + }*/ } fn get_override(irq: u8) -> Option<&'static Override> { src_overrides().iter().find(|over| over.bus_irq == irq) diff --git a/src/arch/x86_64/stop.rs b/src/arch/x86_64/stop.rs index 1000866..8c928c3 100644 --- a/src/arch/x86_64/stop.rs +++ b/src/arch/x86_64/stop.rs @@ -26,8 +26,11 @@ pub unsafe extern fn kreset() -> ! { pub unsafe extern fn kstop() -> ! { println!("kstop"); - #[cfg(feature = "acpi")] - acpi::set_global_s_state(5); + // FIXME: RPC into userspace, maybe allowing the kernel ACPI scheme to support e.g. registering + // an event queue, so that a special file can only be read/written when about to shut down. + + // #[cfg(feature = "acpi")] + // acpi::set_global_s_state(5); // Magic shutdown code for bochs and qemu (older versions). for c in "Shutdown".bytes() { diff --git a/src/lib.rs b/src/lib.rs index 1b4aa69..9f141dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,6 +46,7 @@ #![feature(asm)] // TODO: Relax requirements of most asm invocations #![cfg_attr(target_arch = "aarch64", feature(llvm_asm))] // TODO: Rewrite using asm! #![feature(concat_idents)] +#![feature(const_btree_new)] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(global_asm)] diff --git a/src/scheme/acpi.rs b/src/scheme/acpi.rs index e3351a7..815b91c 100644 --- a/src/scheme/acpi.rs +++ b/src/scheme/acpi.rs @@ -3,21 +3,20 @@ use core::fmt::Write; use core::str; use core::sync::atomic::{self, AtomicUsize}; +use alloc::boxed::Box; use alloc::collections::BTreeMap; use alloc::vec::Vec; use syscall::data::Stat; use syscall::error::{EACCES, EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; -use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDWR, O_STAT, O_WRONLY}; +use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDWR, O_STAT, O_WRONLY, SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::scheme::{calc_seek_offset_usize, Scheme}; use syscall::{Error, Result}; use syscall::{MODE_DIR, MODE_FILE}; -use spin::{Mutex, RwLock}; +use spin::{Once, RwLock}; -use crate::acpi::sdt::Sdt; -use crate::acpi::SdtSignature; -use crate::paging::{ActivePageTable, TableKind}; +use crate::acpi::{RXSDT_ENUM, RxsdtEnum}; #[derive(Clone, Copy)] struct PhysSlice { @@ -27,422 +26,126 @@ struct PhysSlice { virt: usize, } -/// A scheme used to access ACPI tables needed for some drivers to function (e.g. pcid with the -/// PCIe "MCFG" table). -/// -/// # Layout -/// * `/tables` -/// * _can be listed to retrieve the available tables_ -/// * e.g. MCFG-- -/// * _maybe_ the MADT, in case some userspace driver takes care of the I/O APIC. -/// * _perhaps_ some interface for e.g. power management. -pub struct AcpiScheme { - handles: RwLock>>, - tables: Vec<(SdtSignature, PhysSlice)>, - next_fd: AtomicUsize, -} +/// A scheme used to access the RSDT or XSDT, which is needed for e.g. `acpid` to function. +pub struct AcpiScheme; -const TOPLEVEL_DIR_CONTENTS: &[u8] = b"tables\n"; -const ALLOWED_TABLES: &[[u8; 4]] = &[*b"MCFG", *b"APIC"]; - -// XXX: Why can't core also have something like std::io::Take? It's not even real I/O! -/// An internal wrapper struct that limits the number of bytes that can be fmt-written, in order to -/// properly return the length when reading directories etc. The bytes that cannot be written will -/// be discarded. -struct Take<'a> { - buf: &'a mut [u8], +struct Handle { offset: usize, } -impl Take<'_> { - pub fn write_to_buf<'a>(buf: &'a mut [u8]) -> Take<'a> { - Take { offset: 0, buf } - } - pub fn bytes_currently_written(&self) -> usize { - self.offset - } -} +static HANDLES: RwLock> = RwLock::new(BTreeMap::new()); +static NEXT_FD: AtomicUsize = AtomicUsize::new(0); -impl<'a> core::fmt::Write for Take<'a> { - fn write_str(&mut self, string: &str) -> core::fmt::Result { - if self.offset > self.buf.len() { - return Ok(()); - } - - let string_bytes = string.as_bytes(); - let max = core::cmp::min(string_bytes.len() + self.offset, self.buf.len()) - self.offset; - self.buf[self.offset..self.offset + max].copy_from_slice(&string_bytes[..max]); - self.offset += max; - Ok(()) - } -} - -enum Handle { - TopLevel(usize), // seek offset - Tables(usize), // seek offset - - Table { - name: [u8; 4], - oem_id: [u8; 6], - oem_table_id: [u8; 8], - - offset: usize, // seek offset - }, -} +static DATA: Once> = Once::new(); impl AcpiScheme { - fn get_tables() -> Vec<(SdtSignature, PhysSlice)> { - let mut active_table = unsafe { ActivePageTable::new(TableKind::Kernel) }; - - let mut tables = Vec::new(); - - for allowed_tbl_name in ALLOWED_TABLES.iter() { - use crate::acpi::{find_sdt, get_sdt, get_sdt_signature}; - - // it appears that the SDTs are identity mapped, in which case we can just call get_sdt - // whenever we need to and use the slice as if it was physical. - - let table_name_str = - str::from_utf8(allowed_tbl_name).expect("ACPI table name wasn't correct UTF-8"); - - for sdt in find_sdt(table_name_str) { - let virt = - get_sdt(sdt as *const Sdt as usize, &mut active_table) as *const Sdt as usize; - let signature = get_sdt_signature(sdt); - let sdt_pointer = sdt as *const Sdt as usize; - let len = sdt.length as usize; - assert_eq!(virt, sdt_pointer); - tables.push(( - signature, - PhysSlice { - phys_ptr: sdt_pointer, - len, - virt, - }, - )); - } - } - tables - } pub fn new() -> Self { - Self { - handles: RwLock::new(BTreeMap::new()), - tables: Self::get_tables(), - next_fd: AtomicUsize::new(0), + // NOTE: This __must__ be called from the main kernel context, while initializing all + // schemes. If it is called by any other context, then all ACPI data will probably not even + // be mapped. + + let mut initialized = false; + + DATA.call_once(|| { + let rsdt_or_xsdt = RXSDT_ENUM + .r#try() + .expect("expected RXSDT_ENUM to be initialized before AcpiScheme"); + + let table = match rsdt_or_xsdt { + RxsdtEnum::Rsdt(rsdt) => rsdt.as_slice(), + RxsdtEnum::Xsdt(xsdt) => xsdt.as_slice(), + }; + + Box::from(table) + }); + + if !initialized { + log::error!("AcpiScheme::init called multiple times"); } - } - fn lookup_signature_index( - &self, - name: [u8; 4], - oem_id: [u8; 6], - oem_table_id: [u8; 8], - ) -> Option { - self.tables - .iter() - .position(|((sig_name, sig_oem_id, sig_oem_table_id), _)| { - sig_name.as_bytes() == &name - && sig_oem_id == &oem_id - && sig_oem_table_id == &oem_table_id - }) - } - fn lookup_signature( - &self, - name: [u8; 4], - oem_id: [u8; 6], - oem_table_id: [u8; 8], - ) -> Option { - Some(self.tables[self.lookup_signature_index(name, oem_id, oem_table_id)?].1) - } -} -fn parse_table_filename(filename: &[u8]) -> Option<([u8; 4], [u8; 6], [u8; 8])> { - // the table identifier takes the form: - // 1. a four byte table name, like 'APIC' (MADT) or 'MCFG'. - // 2. a dash followed by 12 hexadecimal digits (6 bytes when decoded) composing the OEM ID. - // 3. another dash followed by 16 hex digits (8 bytes), composing the OEM Table ID. - // hence, the table is 4 + 1 + 12 + 1 + 16 = 34 bytes long. - if filename.len() != 34 { - return None; + Self } - let mut table_identifier = [0u8; 34]; - table_identifier.copy_from_slice(filename); - - let table_name = &table_identifier[..4]; - if table_identifier[4] != b'-' { - return None; - } - let oem_id_hex = &table_identifier[5..17]; - if table_identifier[17] != b'-' { - return None; - } - let oem_table_id_hex = &table_identifier[18..34]; - - let oem_id_hex_str = str::from_utf8(oem_id_hex).ok()?; - let oem_table_id_hex_str = str::from_utf8(oem_table_id_hex).ok()?; - - let mut oem_id = [0u8; 6]; - - for index in 0..oem_id.len() { - oem_id[index] = u8::from_str_radix(&oem_id_hex_str[index * 2..(index + 1) * 2], 16).ok()?; - } - - let mut oem_table_id = [0u8; 8]; - - for index in 0..oem_table_id.len() { - oem_table_id[index] = - u8::from_str_radix(&oem_table_id_hex_str[index * 2..(index + 1) * 2], 16).ok()?; - } - - Some((table_name.try_into().unwrap(), oem_id, oem_table_id)) -} -fn serialize_table_filename( - buffer: &mut [u8], - (table_name, oem_id, oem_table_id): ([u8; 4], [u8; 6], [u8; 8]), -) -> usize { - let mut wrapper = Take::write_to_buf(buffer); - write!( - wrapper, - "{}-", - str::from_utf8(&table_name).expect("Acpi table id wasn't valid UTF-8") - ) - .unwrap(); - for b in &oem_id { - write!(wrapper, "{:2x}", b).unwrap(); - } - write!(wrapper, "-").unwrap(); - for b in &oem_table_id { - write!(wrapper, "{:2x}", b).unwrap(); - } - wrapper.bytes_currently_written() } impl Scheme for AcpiScheme { - fn open(&self, path: &str, flags: usize, opener_uid: u32, _opener_gid: u32) -> Result { + fn open(&self, _path: &str, flags: usize, opener_uid: u32, _opener_gid: u32) -> Result { if opener_uid != 0 { return Err(Error::new(EACCES)); } + if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT { + return Err(Error::new(ENOTDIR)); + } - let path_str = path.trim_start_matches('/'); + let fd = NEXT_FD.fetch_add(1, atomic::Ordering::Relaxed); - // TODO: Use some kind of component iterator. + let mut handles_guard = HANDLES.write(); + let handle = Handle { offset: 0 }; - let new_handle = if path_str.starts_with("tables") { - let subpath = (&path_str[6..]).trim_start_matches('/'); + let _ = handles_guard.insert(fd, handle); - if subpath.is_empty() { - // List of ACPI tables - if (flags & O_DIRECTORY == 0 && flags & O_STAT == 0) - || (flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR) - { - return Err(Error::new(EISDIR)); - } - Handle::Tables(0) - } else { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - if flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR { - return Err(Error::new(EINVAL)); - } - let (name, oem_id, oem_table_id) = - parse_table_filename(subpath.as_bytes()).ok_or(Error::new(ENOENT))?; - - if self - .lookup_signature_index(name, oem_id, oem_table_id) - .is_none() - { - return Err(Error::new(ENOENT)); - } - Handle::Table { - name, - oem_id, - oem_table_id, - offset: 0, - } - } - } else if path.is_empty() { - // Top-level - if (flags & O_DIRECTORY == 0 && flags & O_STAT == 0) - || (flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR) - { - return Err(Error::new(EISDIR)); - } - Handle::TopLevel(0) - } else { - return Err(Error::new(ENOENT)); - }; - let new_fd = self.next_fd.fetch_add(1, atomic::Ordering::SeqCst); - self.handles.write().insert(new_fd, Mutex::new(new_handle)); - Ok(new_fd) - } - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let handles_guard = self.handles.read(); - let handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?.lock(); - - Ok(match &*handle { - &Handle::TopLevel(_) => { - let path = b"acpi:"; - let max = core::cmp::min(buf.len(), path.len()); - buf[..max].copy_from_slice(&path[..]); - max - } - &Handle::Tables(_) => { - let path = b"acpi:tables"; - let max = core::cmp::min(buf.len(), path.len()); - buf[..max].copy_from_slice(&path[..]); - max - } - &Handle::Table { - name, - oem_id, - oem_table_id, - .. - } => { - let base_path = b"acpi:tables/"; - let base_max = core::cmp::min(buf.len(), base_path.len()); - buf[..base_max].copy_from_slice(&base_path[..]); - serialize_table_filename(&mut buf[base_max..], (name, oem_id, oem_table_id)) - } - }) + Ok(fd) } fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles_guard = self.handles.read(); - let handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?.lock(); - - match &*handle { - &Handle::TopLevel(_) => { - stat.st_mode = MODE_DIR; - stat.st_size = TOPLEVEL_DIR_CONTENTS.len() as u64; - } - &Handle::Tables(_) => { - stat.st_mode = MODE_DIR; - stat.st_size = (self.tables.len() * 35) as u64; // fixed size of 34 bytes for the file names, plus a newline - } - &Handle::Table { - name, - oem_id, - oem_table_id, - .. - } => { - let len = self - .lookup_signature(name, oem_id, oem_table_id) - .ok_or(Error::new(EBADFD))? - .len; - - stat.st_mode = MODE_FILE; - stat.st_size = len as u64; - } + if ! HANDLES.read().contains_key(&id) { + return Err(Error::new(EBADF)); } + + let data = DATA.r#try().ok_or(Error::new(EBADFD))?; + + stat.st_mode = MODE_FILE; + stat.st_size = data.len().try_into().unwrap_or(u64::max_value()); + Ok(0) } fn seek(&self, id: usize, pos: isize, whence: usize) -> Result { - let handles_guard = self.handles.read(); - let mut handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?.lock(); + let mut handles = HANDLES.write(); + let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let (cur_offset, length) = match &*handle { - &Handle::TopLevel(offset) => (offset, TOPLEVEL_DIR_CONTENTS.len()), - &Handle::Tables(offset) => (offset, (self.tables.len() * 35)), - &Handle::Table { - name, - oem_id, - oem_table_id, - offset, - } => ( - offset, - self.lookup_signature(name, oem_id, oem_table_id) - .ok_or(Error::new(EBADFD))? - .len, - ), + let data = DATA.r#try().ok_or(Error::new(EBADFD))?; + + let new_offset = match whence { + SEEK_SET => pos as usize, + SEEK_CUR => if pos < 0 { + handle.offset.checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))? + } else { + handle.offset.saturating_add(pos as usize) + } + SEEK_END => if pos < 0 { + data.len().checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))? + } else { + data.len() + } + _ => return Err(Error::new(EINVAL)), }; - let new_offset = calc_seek_offset_usize(cur_offset, pos, whence, length)?; - match &mut *handle { - &mut Handle::Table { ref mut offset, .. } - | &mut Handle::Tables(ref mut offset) - | &mut Handle::TopLevel(ref mut offset) => *offset = new_offset as usize, - } - Ok(new_offset) + + handle.offset = new_offset; + + Ok(new_offset as isize) } - fn read(&self, id: usize, mut buf: &mut [u8]) -> Result { - let handles_guard = self.handles.read(); - let mut handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?.lock(); + fn read(&self, id: usize, dst_buf: &mut [u8]) -> Result { + let mut handles = HANDLES.write(); + let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - match &mut *handle { - &mut Handle::TopLevel(ref mut offset) => { - let max_bytes_to_read = core::cmp::min(buf.len(), TOPLEVEL_DIR_CONTENTS.len()); - let bytes_to_read = core::cmp::max(max_bytes_to_read, *offset) - *offset; - buf[..bytes_to_read] - .copy_from_slice(&TOPLEVEL_DIR_CONTENTS[*offset..*offset + bytes_to_read]); - *offset += bytes_to_read; - Ok(bytes_to_read) - } - &mut Handle::Tables(ref mut offset) => { - if *offset >= self.tables.len() * 35 { - return Ok(0); - } - // one really good thing with fixed size filenames, is that no index has to be - // stored anywhere! - let base_table_index = *offset / 35; - let mut bytes_to_skip = *offset % 35; - let mut bytes_read = 0; + let data = DATA.r#try().ok_or(Error::new(EBADFD))?; - for index in base_table_index..self.tables.len() { - let &(ref name_string, oem_id, oem_table_id) = &self.tables[index].0; - let signature = ( - name_string.as_bytes().try_into().or(Err(Error::new(EIO)))?, - oem_id, - oem_table_id, - ); + let src_offset = core::cmp::min(handle.offset, data.len()); + let src_buf = data + .get(src_offset..) + .expect("expected data to be at least data.len() bytes long"); - let mut src_buf = [0u8; 35]; - serialize_table_filename(&mut src_buf[..34], signature); - src_buf[34] = b'\n'; + let bytes_to_copy = core::cmp::min(dst_buf.len(), src_buf.len()); - let max_bytes_to_read = core::cmp::min(buf.len(), src_buf.len()); - let bytes_to_read = - core::cmp::max(max_bytes_to_read, bytes_to_skip) - bytes_to_skip; - buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); - bytes_read += bytes_to_read; - bytes_to_skip = 0; - buf = &mut buf[bytes_to_read..]; - } - *offset += bytes_read; - Ok(bytes_read) - } - &mut Handle::Table { - name, - oem_id, - oem_table_id, - ref mut offset, - } => { - let index = self - .lookup_signature_index(name, oem_id, oem_table_id) - .ok_or(Error::new(EBADFD))?; - let ( - _, - PhysSlice { - phys_ptr, - len, - virt: old_virt, - }, - ) = self.tables[index]; - assert_eq!(phys_ptr, old_virt); - let new_virt = - crate::acpi::get_sdt(phys_ptr, unsafe { &mut ActivePageTable::new(TableKind::Kernel) }) - as *const Sdt as usize; + dst_buf[..bytes_to_copy].copy_from_slice(&src_buf[..bytes_to_copy]); - let table_contents = - unsafe { core::slice::from_raw_parts(new_virt as *const u8, len) }; - - let max_bytes_to_read = core::cmp::min(buf.len(), table_contents.len()); - let bytes_to_read = core::cmp::max(max_bytes_to_read, *offset) - *offset; - buf[..bytes_to_read] - .copy_from_slice(&table_contents[*offset..*offset + bytes_to_read]); - *offset += bytes_to_read; - Ok(bytes_to_read) - } - } + Ok(bytes_to_copy) } fn write(&self, _id: usize, _buf: &[u8]) -> Result { Err(Error::new(EBADF)) } + fn close(&self, id: usize) -> Result { + if ! HANDLES.read().contains_key(&id) { + return Err(Error::new(EBADF)); + } + Ok(0) + } } From 64b2dd238a3df1ee7e7f0668d9ce961204a4d473 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 10 Mar 2021 12:39:38 +0100 Subject: [PATCH 2/9] Rename the kernel ACPI scheme to `kernel/acpi:`. --- Cargo.lock | 2 +- src/scheme/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2cb7f19..1e2bffd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,7 +168,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.6" +version = "0.2.8" dependencies = [ "bitflags", ] diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index ebb49aa..cccf62e 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -162,7 +162,7 @@ impl SchemeList { // These schemes should only be available on the root #[cfg(all(feature = "acpi", target_arch = "x86_64"))] { - self.insert(ns, "acpi", |_| Arc::new(AcpiScheme::new())).unwrap(); + self.insert(ns, "kernel/acpi", |_| Arc::new(AcpiScheme::new())).unwrap(); } self.insert(ns, "debug", |scheme_id| Arc::new(DebugScheme::new(scheme_id))).unwrap(); self.insert(ns, "initfs", |_| Arc::new(InitFsScheme::new())).unwrap(); From 7ac5bdbae0d7b279323c89e707bc08b5abdbf237 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 10 Mar 2021 14:06:43 +0100 Subject: [PATCH 3/9] WIP: Implement userspace-driven shutdown. --- src/acpi/dmar/mod.rs | 3 +- src/acpi/hpet.rs | 3 +- src/acpi/madt.rs | 3 +- src/acpi/mod.rs | 41 ------ src/arch/x86_64/device/ioapic.rs | 3 - src/arch/x86_64/stop.rs | 25 +++- src/scheme/acpi.rs | 214 +++++++++++++++++++++++++------ src/scheme/mod.rs | 2 +- src/sync/wait_condition.rs | 2 +- 9 files changed, 203 insertions(+), 93 deletions(-) diff --git a/src/acpi/dmar/mod.rs b/src/acpi/dmar/mod.rs index 8b107e2..caf8726 100644 --- a/src/acpi/dmar/mod.rs +++ b/src/acpi/dmar/mod.rs @@ -5,7 +5,7 @@ use self::drhd::Drhd; use crate::memory::Frame; use crate::paging::{ActivePageTable, PageFlags, PhysicalAddress}; -use super::{find_sdt, load_table, get_sdt_signature}; +use super::find_sdt; pub mod drhd; @@ -22,7 +22,6 @@ impl Dmar { pub fn init(active_table: &mut ActivePageTable) { let dmar_sdt = find_sdt("DMAR"); let dmar = if dmar_sdt.len() == 1 { - load_table(get_sdt_signature(dmar_sdt[0])); Dmar::new(dmar_sdt[0]) } else { println!("Unable to find DMAR"); diff --git a/src/acpi/hpet.rs b/src/acpi/hpet.rs index 269fa60..498a668 100644 --- a/src/acpi/hpet.rs +++ b/src/acpi/hpet.rs @@ -6,7 +6,7 @@ use crate::memory::Frame; use crate::paging::{ActivePageTable, PhysicalAddress, Page, PageFlags, VirtualAddress}; use super::sdt::Sdt; -use super::{ACPI_TABLE, find_sdt, load_table, get_sdt_signature}; +use super::{ACPI_TABLE, find_sdt}; #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] @@ -38,7 +38,6 @@ impl Hpet { pub fn init(active_table: &mut ActivePageTable) { let hpet_sdt = find_sdt("HPET"); let hpet = if hpet_sdt.len() == 1 { - load_table(get_sdt_signature(hpet_sdt[0])); Hpet::new(hpet_sdt[0], active_table) } else { println!("Unable to find HPET"); diff --git a/src/acpi/madt.rs b/src/acpi/madt.rs index 031598c..f6dabb6 100644 --- a/src/acpi/madt.rs +++ b/src/acpi/madt.rs @@ -4,7 +4,7 @@ use crate::memory::{allocate_frames, Frame}; use crate::paging::{ActivePageTable, Page, PageFlags, PhysicalAddress, VirtualAddress}; use super::sdt::Sdt; -use super::{find_sdt, load_table, get_sdt_signature}; +use super::find_sdt; use core::intrinsics::{atomic_load, atomic_store}; use core::sync::atomic::Ordering; @@ -31,7 +31,6 @@ impl Madt { pub fn init(active_table: &mut ActivePageTable) { let madt_sdt = find_sdt("APIC"); let madt = if madt_sdt.len() == 1 { - load_table(get_sdt_signature(madt_sdt[0])); Madt::new(madt_sdt[0]) } else { println!("Unable to find MADT"); diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 3d6adeb..348c35f 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -81,11 +81,6 @@ pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: O *sdt_ptrs = Some(BTreeMap::new()); } - { - let mut order = SDT_ORDER.write(); - *order = Some(vec!()); - } - // Search for RSDP if let Some(rsdp) = RSDP::get_rsdp(active_table, already_supplied_rsdps) { info!("RSDP: {:?}", rsdp); @@ -149,7 +144,6 @@ pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: O pub type SdtSignature = (String, [u8; 6], [u8; 8]); pub static SDT_POINTERS: RwLock>> = RwLock::new(None); -pub static SDT_ORDER: RwLock>> = RwLock::new(None); pub fn find_sdt(name: &str) -> Vec<&'static Sdt> { let mut sdts: Vec<&'static Sdt> = vec!(); @@ -170,41 +164,6 @@ pub fn get_sdt_signature(sdt: &'static Sdt) -> SdtSignature { (signature, sdt.oem_id, sdt.oem_table_id) } -pub fn load_table(signature: SdtSignature) { - let mut order = SDT_ORDER.write(); - - if let Some(ref mut o) = *order { - o.push(signature); - } -} - -pub fn get_signature_from_index(index: usize) -> Option { - if let Some(ref order) = *(SDT_ORDER.read()) { - if index < order.len() { - Some(order[index].clone()) - } else { - None - } - } else { - None - } -} - -pub fn get_index_from_signature(signature: SdtSignature) -> Option { - if let Some(ref order) = *(SDT_ORDER.read()) { - let mut i = order.len(); - while i > 0 { - i -= 1; - - if order[i] == signature { - return Some(i); - } - } - } - - None -} - pub struct Acpi { pub hpet: RwLock>, pub next_ctx: RwLock, diff --git a/src/arch/x86_64/device/ioapic.rs b/src/arch/x86_64/device/ioapic.rs index dfd405c..e92d452 100644 --- a/src/arch/x86_64/device/ioapic.rs +++ b/src/arch/x86_64/device/ioapic.rs @@ -24,9 +24,6 @@ impl IoApicRegs { // offset 0x10 unsafe { self.pointer.offset(4) } } - fn read_ioregsel(&self) -> u32 { - unsafe { ptr::read_volatile::(self.ioregsel()) } - } fn write_ioregsel(&mut self, value: u32) { unsafe { ptr::write_volatile::(self.ioregsel() as *mut u32, value) } } diff --git a/src/arch/x86_64/stop.rs b/src/arch/x86_64/stop.rs index 8c928c3..f915d0a 100644 --- a/src/arch/x86_64/stop.rs +++ b/src/arch/x86_64/stop.rs @@ -1,5 +1,10 @@ #[cfg(feature = "acpi")] -use crate::acpi; +use crate::{ + context, + scheme::acpi, + time, +}; + use crate::syscall::io::{Io, Pio}; #[no_mangle] @@ -29,8 +34,22 @@ pub unsafe extern fn kstop() -> ! { // FIXME: RPC into userspace, maybe allowing the kernel ACPI scheme to support e.g. registering // an event queue, so that a special file can only be read/written when about to shut down. - // #[cfg(feature = "acpi")] - // acpi::set_global_s_state(5); + #[cfg(feature = "acpi")] + { + // Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e. + // shutdown). + acpi::register_kstop(); + + // Since this driver is a userspace process, and we do not use any magic like directly + // context switching, we have to wait for the userspace driver to complete, with a timeout. + // + // We switch context, and wait for one second. + while time::monotonic().0 < 1 { + if ! context::switch() { + break; + } + } + } // Magic shutdown code for bochs and qemu (older versions). for c in "Shutdown".bytes() { diff --git a/src/scheme/acpi.rs b/src/scheme/acpi.rs index 815b91c..d09fe69 100644 --- a/src/scheme/acpi.rs +++ b/src/scheme/acpi.rs @@ -1,36 +1,41 @@ use core::convert::TryInto; -use core::fmt::Write; use core::str; use core::sync::atomic::{self, AtomicUsize}; use alloc::boxed::Box; use alloc::collections::BTreeMap; -use alloc::vec::Vec; -use syscall::data::Stat; -use syscall::error::{EACCES, EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; -use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDWR, O_STAT, O_WRONLY, SEEK_SET, SEEK_CUR, SEEK_END}; -use syscall::scheme::{calc_seek_offset_usize, Scheme}; -use syscall::{Error, Result}; -use syscall::{MODE_DIR, MODE_FILE}; - -use spin::{Once, RwLock}; +use spin::{Mutex, Once, RwLock}; use crate::acpi::{RXSDT_ENUM, RxsdtEnum}; +use crate::event; +use crate::scheme::SchemeId; +use crate::sync::WaitCondition; -#[derive(Clone, Copy)] -struct PhysSlice { - phys_ptr: usize, - len: usize, - /// These appear to be identity mapped, so this is technically not needed. - virt: usize, -} +use crate::syscall::data::Stat; +use crate::syscall::error::{EACCES, EBADF, EBADFD, EINTR, EINVAL, EISDIR, ENOENT, ENOTDIR, EROFS}; +use crate::syscall::flag::{ + EventFlags, EVENT_READ, + MODE_CHR, MODE_DIR, MODE_FILE, + O_ACCMODE, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, O_STAT, O_SYMLINK, + SEEK_SET, SEEK_CUR, SEEK_END, +}; +use crate::syscall::scheme::Scheme; +use crate::syscall::error::{Error, Result}; /// A scheme used to access the RSDT or XSDT, which is needed for e.g. `acpid` to function. pub struct AcpiScheme; struct Handle { offset: usize, + kind: HandleKind, + stat: bool, +} +#[derive(Eq, PartialEq)] +enum HandleKind { + TopLevel, + Rxsdt, + ShutdownPipe, } static HANDLES: RwLock> = RwLock::new(BTreeMap::new()); @@ -38,15 +43,50 @@ static NEXT_FD: AtomicUsize = AtomicUsize::new(0); static DATA: Once> = Once::new(); +const TOPLEVEL_CONTENTS: &[u8] = b"rxsdt\nkstop\n"; + +static KSTOP_WAITCOND: WaitCondition = WaitCondition::new(); +static KSTOP_FLAG: Mutex = Mutex::new(false); + +static SCHEME_ID: Once = Once::new(); + +pub fn register_kstop() -> bool { + *KSTOP_FLAG.lock() = true; + let mut waiters_awoken = KSTOP_WAITCOND.notify(); + + if let Some(&acpi_scheme) = SCHEME_ID.r#try() { + let handles = HANDLES.read(); + + for (&fd, _) in handles.iter().filter(|(_, handle)| handle.kind == HandleKind::ShutdownPipe) { + event::trigger(acpi_scheme, fd, EVENT_READ); + waiters_awoken += 1; + } + } else { + log::error!("Calling register_kstop before kernel ACPI scheme was initialized"); + } + + if waiters_awoken == 0 { + log::error!("No userspace ACPI handler was notified when trying to shutdown. This is bad."); + // Let the kernel shutdown without ACPI. + return false; + } + + // TODO: Context switch directly to the waiting context, to avoid annoying timeouts. + true +} + impl AcpiScheme { - pub fn new() -> Self { + pub fn new(id: SchemeId) -> Self { // NOTE: This __must__ be called from the main kernel context, while initializing all // schemes. If it is called by any other context, then all ACPI data will probably not even // be mapped. - let mut initialized = false; + let mut data_init = false; + let mut id_init = false; DATA.call_once(|| { + data_init = true; + let rsdt_or_xsdt = RXSDT_ENUM .r#try() .expect("expected RXSDT_ENUM to be initialized before AcpiScheme"); @@ -58,8 +98,13 @@ impl AcpiScheme { Box::from(table) }); + SCHEME_ID.call_once(|| { + id_init = true; - if !initialized { + id + }); + + if !data_init || !id_init { log::error!("AcpiScheme::init called multiple times"); } @@ -68,40 +113,91 @@ impl AcpiScheme { } impl Scheme for AcpiScheme { - fn open(&self, _path: &str, flags: usize, opener_uid: u32, _opener_gid: u32) -> Result { + fn open(&self, path: &str, flags: usize, opener_uid: u32, _opener_gid: u32) -> Result { + let path = path.trim_start_matches('/'); + if opener_uid != 0 { return Err(Error::new(EACCES)); } - if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT { - return Err(Error::new(ENOTDIR)); + if flags & O_CREAT == O_CREAT { + return Err(Error::new(EROFS)); } + if flags & O_EXCL == O_EXCL || flags & O_SYMLINK == O_SYMLINK { + return Err(Error::new(EINVAL)); + } + if flags & O_ACCMODE != O_RDONLY && flags & O_STAT != O_STAT { + return Err(Error::new(EROFS)); + } + let handle_kind = match path { + "" => { + if flags & O_DIRECTORY != O_DIRECTORY && flags & O_STAT != O_STAT { + return Err(Error::new(EISDIR)); + } + + HandleKind::TopLevel + } + "rxsdt" => { + if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT { + return Err(Error::new(ENOTDIR)); + } + HandleKind::Rxsdt + } + "kstop" => { + if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT { + return Err(Error::new(ENOTDIR)); + } + HandleKind::ShutdownPipe + } + _ => return Err(Error::new(ENOENT)), + }; let fd = NEXT_FD.fetch_add(1, atomic::Ordering::Relaxed); - let mut handles_guard = HANDLES.write(); - let handle = Handle { offset: 0 }; - let _ = handles_guard.insert(fd, handle); + let _ = handles_guard.insert(fd, Handle { + offset: 0, + kind: handle_kind, + stat: flags & O_STAT == O_STAT, + }); Ok(fd) } fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - if ! HANDLES.read().contains_key(&id) { - return Err(Error::new(EBADF)); + let handles = HANDLES.read(); + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + + match handle.kind { + HandleKind::Rxsdt => { + let data = DATA.r#try().ok_or(Error::new(EBADFD))?; + + stat.st_mode = MODE_FILE; + stat.st_size = data.len().try_into().unwrap_or(u64::max_value()); + } + HandleKind::TopLevel => { + stat.st_mode = MODE_DIR; + stat.st_size = TOPLEVEL_CONTENTS.len().try_into().unwrap_or(u64::max_value()); + } + HandleKind::ShutdownPipe => { + stat.st_mode = MODE_CHR; + stat.st_size = 1; + } } - let data = DATA.r#try().ok_or(Error::new(EBADFD))?; - - stat.st_mode = MODE_FILE; - stat.st_size = data.len().try_into().unwrap_or(u64::max_value()); - Ok(0) } fn seek(&self, id: usize, pos: isize, whence: usize) -> Result { let mut handles = HANDLES.write(); let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let data = DATA.r#try().ok_or(Error::new(EBADFD))?; + if handle.stat { + return Err(Error::new(EBADF)); + } + + let file_len = match handle.kind { + HandleKind::Rxsdt => DATA.r#try().ok_or(Error::new(EBADFD))?.len(), + HandleKind::ShutdownPipe => 1, + HandleKind::TopLevel => TOPLEVEL_CONTENTS.len(), + }; let new_offset = match whence { SEEK_SET => pos as usize, @@ -111,9 +207,9 @@ impl Scheme for AcpiScheme { handle.offset.saturating_add(pos as usize) } SEEK_END => if pos < 0 { - data.len().checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))? + file_len.checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))? } else { - data.len() + file_len } _ => return Err(Error::new(EINVAL)), }; @@ -126,7 +222,38 @@ impl Scheme for AcpiScheme { let mut handles = HANDLES.write(); let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let data = DATA.r#try().ok_or(Error::new(EBADFD))?; + if handle.stat { + return Err(Error::new(EBADF)); + } + + let data = match handle.kind { + HandleKind::ShutdownPipe => { + let dst_byte = match dst_buf.first_mut() { + None => return Ok(0), + Some(dst) => if handle.offset >= 1 { + return Ok(0) + } else { + dst + }, + }; + + loop { + let flag_guard = KSTOP_FLAG.lock(); + + if *flag_guard { + break; + } else if ! KSTOP_WAITCOND.wait(flag_guard, "waiting for kstop") { + return Err(Error::new(EINTR)); + } + } + + *dst_byte = 0x42; + handle.offset = 1; + return Ok(1); + } + HandleKind::Rxsdt => DATA.r#try().ok_or(Error::new(EBADFD))?, + HandleKind::TopLevel => TOPLEVEL_CONTENTS, + }; let src_offset = core::cmp::min(handle.offset, data.len()); let src_buf = data @@ -136,14 +263,25 @@ impl Scheme for AcpiScheme { let bytes_to_copy = core::cmp::min(dst_buf.len(), src_buf.len()); dst_buf[..bytes_to_copy].copy_from_slice(&src_buf[..bytes_to_copy]); + handle.offset += bytes_to_copy; Ok(bytes_to_copy) } + fn fevent(&self, id: usize, flags: EventFlags) -> Result { + let handles = HANDLES.read(); + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + Ok(EventFlags::empty()) + } fn write(&self, _id: usize, _buf: &[u8]) -> Result { Err(Error::new(EBADF)) } fn close(&self, id: usize) -> Result { - if ! HANDLES.read().contains_key(&id) { + if HANDLES.write().remove(&id).is_none() { return Err(Error::new(EBADF)); } Ok(0) diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index cccf62e..74405b0 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -162,7 +162,7 @@ impl SchemeList { // These schemes should only be available on the root #[cfg(all(feature = "acpi", target_arch = "x86_64"))] { - self.insert(ns, "kernel/acpi", |_| Arc::new(AcpiScheme::new())).unwrap(); + self.insert(ns, "kernel/acpi", |scheme_id| Arc::new(AcpiScheme::new(scheme_id))).unwrap(); } self.insert(ns, "debug", |scheme_id| Arc::new(DebugScheme::new(scheme_id))).unwrap(); self.insert(ns, "initfs", |_| Arc::new(InitFsScheme::new())).unwrap(); diff --git a/src/sync/wait_condition.rs b/src/sync/wait_condition.rs index 2865bd3..8f6566e 100644 --- a/src/sync/wait_condition.rs +++ b/src/sync/wait_condition.rs @@ -10,7 +10,7 @@ pub struct WaitCondition { } impl WaitCondition { - pub fn new() -> WaitCondition { + pub const fn new() -> WaitCondition { WaitCondition { contexts: Mutex::new(Vec::new()) } From b2e131b57b2ddb4d86e69b4e93440b8c0b644d08 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 11 Mar 2021 12:48:47 +0100 Subject: [PATCH 4/9] Fix ACPI scheme fevent warning. --- src/scheme/acpi.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scheme/acpi.rs b/src/scheme/acpi.rs index d09fe69..c56a581 100644 --- a/src/scheme/acpi.rs +++ b/src/scheme/acpi.rs @@ -267,7 +267,8 @@ impl Scheme for AcpiScheme { Ok(bytes_to_copy) } - fn fevent(&self, id: usize, flags: EventFlags) -> Result { + // TODO + fn fevent(&self, id: usize, _flags: EventFlags) -> Result { let handles = HANDLES.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; From 9b4ce0d0ccd38df8c02381614239be3e54fe9751 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 11 Mar 2021 17:32:28 +0100 Subject: [PATCH 5/9] WIP: Fix userspace ACPI shutdown. --- src/arch/x86_64/stop.rs | 54 +++++++++++++++++++++++++++-------------- src/context/context.rs | 2 +- src/syscall/process.rs | 38 +++++++++++++++-------------- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/src/arch/x86_64/stop.rs b/src/arch/x86_64/stop.rs index f915d0a..eadc8c3 100644 --- a/src/arch/x86_64/stop.rs +++ b/src/arch/x86_64/stop.rs @@ -27,29 +27,47 @@ pub unsafe extern fn kreset() -> ! { unreachable!(); } -#[no_mangle] -pub unsafe extern fn kstop() -> ! { - println!("kstop"); +#[cfg(feature = "acpi")] +fn userspace_acpi_shutdown() { + log::info!("Notifying any potential ACPI driver"); + // Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e. + // shutdown). + if ! acpi::register_kstop() { + // There was no context to switch to. + log::info!("No ACPI driver was alive to handle shutdown."); + return; + } + log::info!("Waiting one second for ACPI driver to run the shutdown sequence."); + let (initial_s, initial_ns) = time::monotonic(); - // FIXME: RPC into userspace, maybe allowing the kernel ACPI scheme to support e.g. registering - // an event queue, so that a special file can only be read/written when about to shut down. + // Since this driver is a userspace process, and we do not use any magic like directly + // context switching, we have to wait for the userspace driver to complete, with a timeout. + // + // We switch context, and wait for one second. + loop { + // TODO: Switch directly to whichever process is handling the kstop pipe. We would add an + // event flag like EVENT_DIRECT, which has already been suggested for IRQs. + // TODO: Waitpid with timeout? Because, what if the ACPI driver would crash? + let _ = unsafe { context::switch() }; + let (current_s, current_ns) = time::monotonic(); - #[cfg(feature = "acpi")] - { - // Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e. - // shutdown). - acpi::register_kstop(); + let diff_s = current_s - initial_s; + let diff_part_ns = current_ns - initial_ns; + let diff_ns = diff_s * 1_000_000_000 + diff_part_ns; - // Since this driver is a userspace process, and we do not use any magic like directly - // context switching, we have to wait for the userspace driver to complete, with a timeout. - // - // We switch context, and wait for one second. - while time::monotonic().0 < 1 { - if ! context::switch() { - break; - } + if diff_ns > 1_000_000_000 { + log::info!("Timeout reached, thus falling back to other shutdown methods."); + return; } } +} + +#[no_mangle] +pub unsafe extern fn kstop() -> ! { + log::info!("Running kstop()"); + + #[cfg(feature = "acpi")] + userspace_acpi_shutdown(); // Magic shutdown code for bochs and qemu (older versions). for c in "Shutdown".bytes() { diff --git a/src/context/context.rs b/src/context/context.rs index 5d6b444..299e303 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -34,7 +34,7 @@ pub enum Status { Runnable, Blocked, Stopped(usize), - Exited(usize) + Exited(usize), } #[derive(Copy, Clone, Debug)] diff --git a/src/syscall/process.rs b/src/syscall/process.rs index db2d2bd..f62721a 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -1128,6 +1128,8 @@ pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) - pub fn exit(status: usize) -> ! { ptrace::breakpoint_callback(PTRACE_STOP_EXIT, Some(ptrace_event!(PTRACE_STOP_EXIT, status))); + let pid; + { let context_lock = { let contexts = context::contexts(); @@ -1136,7 +1138,7 @@ pub fn exit(status: usize) -> ! { }; let mut close_files = Vec::new(); - let pid = { + pid = { let mut context = context_lock.write(); { let mut lock = context.files.write(); @@ -1148,6 +1150,22 @@ pub fn exit(status: usize) -> ! { context.id }; + // TODO: Find a better way to implement this, perhaps when the init process calls exit. + if pid == ContextId::from(1) { + println!("Main kernel thread exited with status {:X}", status); + + extern { + fn kreset() -> !; + fn kstop() -> !; + } + + if status == SIGTERM { + unsafe { kreset(); } + } else { + unsafe { kstop(); } + } + } + // Files must be closed while context is valid so that messages can be passed for (_fd, file_opt) in close_files.drain(..).enumerate() { if let Some(file) = file_opt { @@ -1214,26 +1232,10 @@ pub fn exit(status: usize) -> ! { // Alert any tracers waiting of this process ptrace::close_tracee(pid); - - if pid == ContextId::from(1) { - println!("Main kernel thread exited with status {:X}", status); - - extern { - fn kreset() -> !; - fn kstop() -> !; - } - - if status == SIGTERM { - unsafe { kreset(); } - } else { - unsafe { kstop(); } - } - } } let _ = unsafe { context::switch() }; - - unreachable!(); + unreachable!() } pub fn getpid() -> Result { From e816d4801fbd44aade725eed56f43a9dbd94ac54 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 13 Mar 2021 10:30:37 +0100 Subject: [PATCH 6/9] Remove the empty fadt module. --- src/acpi/fadt.rs | 0 src/acpi/mod.rs | 1 - 2 files changed, 1 deletion(-) delete mode 100644 src/acpi/fadt.rs diff --git a/src/acpi/fadt.rs b/src/acpi/fadt.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 348c35f..edbe29c 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -23,7 +23,6 @@ use self::rsdp::RSDP; pub mod hpet; mod dmar; -mod fadt; pub mod madt; mod rsdt; pub mod sdt; From a771ca699aa47c825d0486354005a8207bf77a40 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 13 Mar 2021 12:33:20 +0100 Subject: [PATCH 7/9] Move all DMAR parsing to userspace. We may also want to do this with the MADT and the HPET tables, and let user drivers specify what the tables mean independent of ACPI. That is, adding an interface for registering new CPUs, and specifying the main timer IRQ. --- src/acpi/dmar/drhd.rs | 77 --------------- src/acpi/dmar/mod.rs | 214 ------------------------------------------ src/acpi/mod.rs | 9 +- 3 files changed, 6 insertions(+), 294 deletions(-) delete mode 100644 src/acpi/dmar/drhd.rs delete mode 100644 src/acpi/dmar/mod.rs diff --git a/src/acpi/dmar/drhd.rs b/src/acpi/dmar/drhd.rs deleted file mode 100644 index 494917e..0000000 --- a/src/acpi/dmar/drhd.rs +++ /dev/null @@ -1,77 +0,0 @@ -#[repr(packed)] -pub struct DrhdFault { - pub sts: u32, - pub ctrl: u32, - pub data: u32, - pub addr: [u32; 2], - _rsv: [u64; 2], - pub log: u64, -} - -#[repr(packed)] -pub struct DrhdProtectedMemory { - pub en: u32, - pub low_base: u32, - pub low_limit: u32, - pub high_base: u64, - pub high_limit: u64, -} - -#[repr(packed)] -pub struct DrhdInvalidation { - pub queue_head: u64, - pub queue_tail: u64, - pub queue_addr: u64, - _rsv: u32, - pub cmpl_sts: u32, - pub cmpl_ctrl: u32, - pub cmpl_data: u32, - pub cmpl_addr: [u32; 2], -} - -#[repr(packed)] -pub struct DrhdPageRequest { - pub queue_head: u64, - pub queue_tail: u64, - pub queue_addr: u64, - _rsv: u32, - pub sts: u32, - pub ctrl: u32, - pub data: u32, - pub addr: [u32; 2], -} - -#[repr(packed)] -pub struct DrhdMtrrVariable { - pub base: u64, - pub mask: u64, -} - -#[repr(packed)] -pub struct DrhdMtrr { - pub cap: u64, - pub def_type: u64, - pub fixed: [u64; 11], - pub variable: [DrhdMtrrVariable; 10], -} - -#[repr(packed)] -pub struct Drhd { - pub version: u32, - _rsv: u32, - pub cap: u64, - pub ext_cap: u64, - pub gl_cmd: u32, - pub gl_sts: u32, - pub root_table: u64, - pub ctx_cmd: u64, - _rsv1: u32, - pub fault: DrhdFault, - _rsv2: u32, - pub pm: DrhdProtectedMemory, - pub invl: DrhdInvalidation, - _rsv3: u64, - pub intr_table: u64, - pub page_req: DrhdPageRequest, - pub mtrr: DrhdMtrr, -} diff --git a/src/acpi/dmar/mod.rs b/src/acpi/dmar/mod.rs deleted file mode 100644 index caf8726..0000000 --- a/src/acpi/dmar/mod.rs +++ /dev/null @@ -1,214 +0,0 @@ -use core::mem; - -use super::sdt::Sdt; -use self::drhd::Drhd; -use crate::memory::Frame; -use crate::paging::{ActivePageTable, PageFlags, PhysicalAddress}; - -use super::find_sdt; - -pub mod drhd; - -/// The DMA Remapping Table -#[derive(Debug)] -pub struct Dmar { - sdt: &'static Sdt, - pub addr_width: u8, - pub flags: u8, - _rsv: [u8; 10], -} - -impl Dmar { - pub fn init(active_table: &mut ActivePageTable) { - let dmar_sdt = find_sdt("DMAR"); - let dmar = if dmar_sdt.len() == 1 { - Dmar::new(dmar_sdt[0]) - } else { - println!("Unable to find DMAR"); - return; - }; - - if let Some(dmar) = dmar { - println!(" DMAR: {}: {}", dmar.addr_width, dmar.flags); - - for dmar_entry in dmar.iter() { - println!(" {:?}", dmar_entry); - match dmar_entry { - DmarEntry::Drhd(dmar_drhd) => { - let drhd = dmar_drhd.get(active_table); - - println!("VER: {:X}", {drhd.version}); - println!("CAP: {:X}", {drhd.cap}); - println!("EXT_CAP: {:X}", {drhd.ext_cap}); - println!("GCMD: {:X}", {drhd.gl_cmd}); - println!("GSTS: {:X}", {drhd.gl_sts}); - println!("RT: {:X}", {drhd.root_table}); - }, - _ => () - } - } - } - } - - pub fn new(sdt: &'static Sdt) -> Option { - if &sdt.signature == b"DMAR" && sdt.data_len() >= 12 { //Not valid if no local address and flags - let addr_width = unsafe { *(sdt.data_address() as *const u8) }; - let flags = unsafe { *(sdt.data_address() as *const u8).offset(1) }; - let rsv: [u8; 10] = unsafe { *((sdt.data_address() as *const u8).offset(2) as *const [u8; 10]) }; - - Some(Dmar { - sdt: sdt, - addr_width: addr_width, - flags: flags, - _rsv: rsv, - }) - } else { - None - } - } - - pub fn iter(&self) -> DmarIter { - DmarIter { - sdt: self.sdt, - i: 12 // Skip address width and flags - } - } -} - -/// DMAR DMA Remapping Hardware Unit Definition -// TODO: Implement iterator on DmarDrhd scope -#[derive(Clone, Copy, Debug)] -#[repr(packed)] -pub struct DmarDrhd { - kind: u16, - length: u16, - flags: u8, - _rsv: u8, - segment: u16, - base: u64, -} - -impl DmarDrhd { - pub fn get(&self, active_table: &mut ActivePageTable) -> &'static mut Drhd { - let result = active_table.identity_map(Frame::containing_address(PhysicalAddress::new(self.base as usize)), PageFlags::new().write(true)); - result.flush(); - unsafe { &mut *(self.base as *mut Drhd) } - } -} - -/// DMAR Reserved Memory Region Reporting -// TODO: Implement iterator on DmarRmrr scope -#[derive(Clone, Copy, Debug)] -#[repr(packed)] -pub struct DmarRmrr { - kind: u16, - length: u16, - _rsv: u16, - segment: u16, - base: u64, - limit: u64, -} - -/// DMAR Root Port ATS Capability Reporting -// TODO: Implement iterator on DmarAtsr scope -#[derive(Clone, Copy, Debug)] -#[repr(packed)] -pub struct DmarAtsr { - kind: u16, - length: u16, - flags: u8, - _rsv: u8, - segment: u16, -} - -/// DMAR Remapping Hardware Static Affinity -#[derive(Clone, Copy, Debug)] -#[repr(packed)] -pub struct DmarRhsa { - kind: u16, - length: u16, - _rsv: u32, - base: u64, - domain: u32, -} - -/// DMAR ACPI Name-space Device Declaration -// TODO: Implement iterator on DmarAndd object name -#[derive(Clone, Copy, Debug)] -#[repr(packed)] -pub struct DmarAndd { - kind: u16, - length: u16, - _rsv: [u8; 3], - acpi_dev: u8, -} - -/// DMAR Entries -#[derive(Debug)] -pub enum DmarEntry { - Drhd(&'static DmarDrhd), - InvalidDrhd(usize), - Rmrr(&'static DmarRmrr), - InvalidRmrr(usize), - Atsr(&'static DmarAtsr), - InvalidAtsr(usize), - Rhsa(&'static DmarRhsa), - InvalidRhsa(usize), - Andd(&'static DmarAndd), - InvalidAndd(usize), - Unknown(u16) -} - -pub struct DmarIter { - sdt: &'static Sdt, - i: usize -} - -impl Iterator for DmarIter { - type Item = DmarEntry; - fn next(&mut self) -> Option { - if self.i + 4 <= self.sdt.data_len() { - let entry_type = unsafe { *((self.sdt.data_address() as *const u8).add(self.i) as *const u16) }; - let entry_len = unsafe { *((self.sdt.data_address() as *const u8).add(self.i + 2) as *const u16) } as usize; - - if self.i + entry_len <= self.sdt.data_len() { - let item = match entry_type { - 0 => if entry_len >= mem::size_of::() { - DmarEntry::Drhd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarDrhd) }) - } else { - DmarEntry::InvalidDrhd(entry_len) - }, - 1 => if entry_len >= mem::size_of::() { - DmarEntry::Rmrr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRmrr) }) - } else { - DmarEntry::InvalidRmrr(entry_len) - }, - 2 => if entry_len >= mem::size_of::() { - DmarEntry::Atsr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAtsr) }) - } else { - DmarEntry::InvalidAtsr(entry_len) - }, - 3 => if entry_len == mem::size_of::() { - DmarEntry::Rhsa(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRhsa) }) - } else { - DmarEntry::InvalidRhsa(entry_len) - }, - 4 => if entry_len >= mem::size_of::() { - DmarEntry::Andd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAndd) }) - } else { - DmarEntry::InvalidAndd(entry_len) - }, - _ => DmarEntry::Unknown(entry_type) - }; - - self.i += entry_len; - - Some(item) - } else { - None - } - } else { - None - } - } -} diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index edbe29c..c75c78b 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -12,7 +12,6 @@ use crate::log::info; use crate::memory::Frame; use crate::paging::{ActivePageTable, Page, PageFlags, PhysicalAddress, VirtualAddress}; -use self::dmar::Dmar; use self::madt::Madt; use self::rsdt::Rsdt; use self::sdt::Sdt; @@ -22,7 +21,6 @@ use self::rxsdt::Rxsdt; use self::rsdp::RSDP; pub mod hpet; -mod dmar; pub mod madt; mod rsdt; pub mod sdt; @@ -122,6 +120,8 @@ pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: O return; }; + // TODO: Don't touch ACPI tables in kernel? + rxsdt.map_all(active_table); for sdt_address in rxsdt.iter() { @@ -133,8 +133,11 @@ pub unsafe fn init(active_table: &mut ActivePageTable, already_supplied_rsdps: O } } + // TODO: Enumerate processors in userspace, and then provide an ACPI-independent interface + // to initialize enumerated processors to userspace? Madt::init(active_table); - Dmar::init(active_table); + // TODO: Let userspace setup HPET, and then provide an interface to specify which timer to + // use? Hpet::init(active_table); } else { println!("NO RSDP FOUND"); From fd97fa80bb2cea9a0659c752b6ef6a1380b53306 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 13 Mar 2021 16:42:00 +0100 Subject: [PATCH 8/9] Move `pid` back to inner scope in exit() handler. --- src/syscall/process.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index f62721a..2e4b897 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -1128,8 +1128,6 @@ pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) - pub fn exit(status: usize) -> ! { ptrace::breakpoint_callback(PTRACE_STOP_EXIT, Some(ptrace_event!(PTRACE_STOP_EXIT, status))); - let pid; - { let context_lock = { let contexts = context::contexts(); @@ -1138,7 +1136,7 @@ pub fn exit(status: usize) -> ! { }; let mut close_files = Vec::new(); - pid = { + let pid = { let mut context = context_lock.write(); { let mut lock = context.files.write(); From 3eacbdda2a0424dd59800a7b15d629e7c6fc79ae Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 13 Mar 2021 16:44:09 +0100 Subject: [PATCH 9/9] Remove unnecessary exit() diff. --- src/syscall/process.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 2e4b897..2667ae7 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -1233,7 +1233,8 @@ pub fn exit(status: usize) -> ! { } let _ = unsafe { context::switch() }; - unreachable!() + + unreachable!(); } pub fn getpid() -> Result {