diff --git a/Cargo.lock b/Cargo.lock index e68091c90e..4322c741b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,16 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "acpid" +version = "0.1.0" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "adler" version = "0.2.3" @@ -141,6 +152,11 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "chashmap" version = "2.2.2" @@ -422,6 +438,14 @@ dependencies = [ "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "iovec" version = "0.1.4" @@ -483,6 +507,14 @@ dependencies = [ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.8" @@ -622,7 +654,7 @@ dependencies = [ "pcid 0.1.0", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -637,7 +669,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#d212107f84183a1 dependencies = [ "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -659,6 +691,16 @@ dependencies = [ "parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot_core" version = "0.7.2" @@ -668,7 +710,20 @@ dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -732,7 +787,7 @@ dependencies = [ "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -965,7 +1020,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0#30f6 dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -992,7 +1047,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1131,7 +1186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "1.4.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1296,7 +1351,7 @@ name = "unicode-normalization" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1411,7 +1466,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1486,7 +1541,7 @@ dependencies = [ "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1510,6 +1565,7 @@ dependencies = [ "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" "checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" @@ -1539,6 +1595,7 @@ dependencies = [ "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" "checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" @@ -1547,6 +1604,7 @@ dependencies = [ "checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" "checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" "checksum lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +"checksum lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" @@ -1565,7 +1623,9 @@ dependencies = [ "checksum orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)" = "" "checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" "checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +"checksum parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" "checksum parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +"checksum parking_lot_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" "checksum paw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" "checksum paw-attributes 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" @@ -1599,7 +1659,7 @@ dependencies = [ "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" "checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" -"checksum redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "48b82c2a1e8eb6e1bfde608de2bcbebd4072aa32d056ea48a986990cd5ca0f5a" +"checksum redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" @@ -1614,7 +1674,7 @@ dependencies = [ "checksum serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" "checksum serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" +"checksum smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" diff --git a/Cargo.toml b/Cargo.toml index b9af329cd3..28ffd6b8a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "acpid", "ahcid", "alxd", "bgad", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml new file mode 100644 index 0000000000..30041ea4fd --- /dev/null +++ b/acpid/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "acpid" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4" +parking_lot = "0.11.1" +plain = "0.2.3" +redox_syscall = "0.2.5" +thiserror = "1" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs new file mode 100644 index 0000000000..10ece8899f --- /dev/null +++ b/acpid/src/acpi.rs @@ -0,0 +1,443 @@ +use std::collections::HashMap; +use std::convert::{TryFrom, TryInto}; +use std::mem; +use std::ops::Deref; +use std::sync::Arc; + +use syscall::flag::PhysmapFlags; + +use thiserror::Error; + +use super::aml::AmlValue; + +#[cfg(target_arch = "x86_64")] +pub const PAGE_SIZE: usize = 4096; + +/// The raw SDT header struct, as defined by the ACPI specification. +#[derive(Copy, Clone, Debug)] +#[repr(packed)] +pub struct SdtHeader { + pub signature: [u8; 4], + pub length: u32, + pub revision: u8, + pub checksum: u8, + pub oem_id: [u8; 6], + pub oem_table_id: [u8; 8], + pub oem_revision: u32, + pub creator_id: u32, + pub creator_revision: u32, +} +unsafe impl plain::Plain for SdtHeader {} + +impl SdtHeader { + pub fn signature(&self) -> SdtSignature { + SdtSignature { + signature: self.signature, + oem_id: self.oem_id, + oem_table_id: self.oem_table_id, + } + } + fn length(&self) -> usize { + self + .length + .try_into() + .expect("expected usize to be at least 32 bits") + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub struct SdtSignature { + pub signature: [u8; 4], + pub oem_id: [u8; 6], + pub oem_table_id: [u8; 8], +} + +#[derive(Debug, Error)] +pub enum TablePhysLoadError { + // TODO: Make syscall::Error implement std::error::Error, when enabling a Cargo feature. + #[error("i/o error: {0}")] + Io(#[from] std::io::Error), + + #[error("invalid SDT: {0}")] + Validity(#[from] InvalidSdtError), +} +#[derive(Debug, Error)] +pub enum InvalidSdtError { + #[error("invalid size")] + InvalidSize, + + #[error("invalid checksum")] + BadChecksum, +} + +struct PhysmapGuard { + virt: *const u8, + size: usize, +} +impl PhysmapGuard { + fn map(page: usize, page_count: usize) -> std::io::Result { + let size = page_count * PAGE_SIZE; + let virt = unsafe { + syscall::call::physmap(page, size, PhysmapFlags::empty()) + .map_err(|error| std::io::Error::from_raw_os_error(error.errno))? + }; + + Ok(Self { + virt: virt as *const u8, + size, + }) + } +} +impl Deref for PhysmapGuard { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + unsafe { + std::slice::from_raw_parts(self.virt as *const u8, self.size) + } + } +} +impl Drop for PhysmapGuard { + fn drop(&mut self) { + unsafe { + syscall::physfree(self.virt as usize, self.size); + } + } +} + +#[derive(Clone)] +pub struct Sdt(Arc<[u8]>); + +impl Sdt { + pub fn new(slice: Arc<[u8]>) -> Result { + let header = match plain::from_bytes::(&slice) { + Ok(header) => header, + Err(plain::Error::TooShort) => return Err(InvalidSdtError::InvalidSize), + Err(plain::Error::BadAlignment) => panic!("plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)]!"), + }; + + if header.length() != slice.len() { + return Err(InvalidSdtError::InvalidSize); + } + + let checksum = slice.iter().copied().fold(0_u8, |current_sum, item| current_sum.wrapping_add(item)); + + if checksum != 0 { + return Err(InvalidSdtError::BadChecksum); + } + + Ok(Self(slice)) + } + pub fn load_from_physical(physaddr: usize) -> Result { + let physaddr_start_page = physaddr / PAGE_SIZE * PAGE_SIZE; + let physaddr_page_offset = physaddr % PAGE_SIZE; + + // Begin by reading and validating the header first. The SDT header is always 36 bytes + // long, and can thus span either one or two page table frames. + let needs_extra_page = (PAGE_SIZE - physaddr_page_offset).checked_sub(mem::size_of::()).is_none(); + let page_table_count = 1 + if needs_extra_page { 1 } else { 0 }; + + let pages = PhysmapGuard::map(physaddr_start_page, page_table_count)?; + assert!(pages.len() >= mem::size_of::()); + let sdt_mem = &pages[physaddr_page_offset..]; + + let sdt = plain::from_bytes::(&pages[mem::size_of::()..]) + .expect("either alignment is wrong, or the length is too short, both of which are already checked for"); + + let total_length = sdt.length(); + let base_length = std::cmp::min(total_length, sdt_mem.len()); + let extended_length = total_length - base_length; + + let mut loaded = sdt_mem[..base_length].to_owned(); + loaded.reserve(extended_length); + + const SIMULTANEOUS_PAGE_COUNT: usize = 4; + + let mut left = extended_length; + let mut offset = physaddr_start_page + page_table_count * PAGE_SIZE; + let length_per_iteration = PAGE_SIZE * SIMULTANEOUS_PAGE_COUNT; + + while left > 0 { + let to_copy = std::cmp::min(left, length_per_iteration); + let pages = PhysmapGuard::map(offset, length_per_iteration)?; + + loaded.extend(&pages[..to_copy]); + + left -= to_copy; + offset += to_copy; + } + assert_eq!(offset, loaded.len()); + + Self::new(loaded.into()).map_err(Into::into) + } +} + +impl Deref for Sdt { + type Target = SdtHeader; + + fn deref(&self) -> &Self::Target { + plain::from_bytes::(&self.0) + .expect("expected already validated Sdt to be able to get its header") + } +} + +impl Sdt { + pub fn data(&self) -> &[u8] { + &self.0[mem::size_of::()..] + } +} + +pub struct Dsdt(Sdt); +pub struct Ssdt(Sdt); + +pub struct AcpiContext { + tables: Vec, + dsdt: Option, + fadt: Option, + namespace: Option>, +} +impl AcpiContext { + pub fn dsdt(&self) -> Option<&Dsdt> { + self.dsdt.as_ref() + } + pub fn ssdts(&self) -> impl Iterator + '_ { + self.find_multiple_sdts(*b"SSDT").map(|sdt| Ssdt(sdt.clone())) + } + fn find_single_sdt_pos(&self, signature: [u8; 4]) -> Option { + let count = self.tables.iter().filter(|sdt| sdt.signature == signature).count(); + + if count > 1 { + log::warn!("Expected only a single SDT of signature `{}` ({:?}), but there were {}", String::from_utf8_lossy(&signature), signature, count); + } + + self.tables.iter().position(|sdt| sdt.signature == signature) + } + pub fn find_single_sdt(&self, signature: [u8; 4]) -> Option<&Sdt> { + self.find_single_sdt_pos(signature).map(|pos| &self.tables[pos]) + } + pub fn find_multiple_sdts<'a>(&'a self, signature: [u8; 4]) -> impl Iterator { + self.tables.iter().filter(move |sdt| sdt.signature == signature) + } + pub fn take_single_sdt(&mut self, signature: [u8; 4]) -> Option { + self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone()) + } + pub fn namespace(&self) -> Option<&HashMap> { + self.namespace.as_ref() + } + pub fn fadt(&self) -> Option<&Fadt> { + self.fadt.as_ref() + } + pub fn sdt_from_signature(&self, signature: &SdtSignature) -> Option<&Sdt> { + self.tables.iter().find(|sdt| sdt.signature == signature.signature && sdt.oem_id == signature.oem_id && sdt.oem_table_id == signature.oem_table_id) + } + pub fn get_signature_from_index(&self, index: usize) -> Option { + todo!() + } + pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option { + todo!() + } +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct FadtStruct { + pub header: SdtHeader, + 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, +} +unsafe impl plain::Plain for FadtStruct {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct GenericAddressStructure { + address_space: u8, + bit_width: u8, + bit_offset: u8, + access_size: u8, + address: u64, +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct FadtAcpi2Struct { + // 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, +} +unsafe impl plain::Plain for FadtAcpi2Struct {} + +pub struct Fadt(Sdt); + +impl Fadt { + pub fn acpi_2_struct(&self) -> Option<&FadtAcpi2Struct> { + let bytes = &self.0.0[mem::size_of::()..]; + + match plain::from_bytes::(bytes) { + Ok(fadt2) => Some(fadt2), + Err(plain::Error::TooShort) => None, + Err(plain::Error::BadAlignment) => unreachable!("plain::from_bytes reported bad alignment, but FadtAcpi2Struct is #[repr(packed)]"), + } + } +} + +impl Deref for Fadt { + type Target = FadtStruct; + + fn deref(&self) -> &Self::Target { + plain::from_bytes::(&self.0.0) + .expect("expected FADT struct to already be validated in Deref impl") + } +} + +impl Fadt { + pub fn new(context: &AcpiContext, sdt: Sdt) -> Option { + if sdt.signature != *b"FACP" || sdt.length() < mem::size_of::() { + return None; + } + Some(Fadt(sdt)) + } + + pub fn init(context: &mut AcpiContext) { + let fadt_sdt = context + .take_single_sdt(*b"FACP") + .expect("expected ACPI to always have a FADT"); + + let fadt = match Fadt::new(context, fadt_sdt) { + Some(fadt) => fadt, + None => { + log::error!("Failed to find FADT"); + return; + } + }; + + let dsdt_ptr = match fadt.acpi_2_struct() { + Some(fadt2) => usize::try_from(fadt2.x_dsdt).unwrap_or_else(|_| { + usize::try_from(fadt.dsdt) + .expect("expected any given u32 to fit within usize") + }), + None => usize::try_from(fadt.dsdt) + .expect("expected any given u32 to fit within usize") + }; + + log::info!(" FACP: {:X}", {dsdt_ptr}); + + let dsdt_sdt = match Sdt::load_from_physical(fadt.dsdt as usize) { + Ok(dsdt) => dsdt, + Err(error) => { + log::error!("Failed to load DSDT: {}", error); + return; + } + }; + + context.dsdt = Some(Dsdt(dsdt_sdt)); + + /* + let signature = get_sdt_signature(dsdt_sdt); + if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) { + ptrs.insert(signature, dsdt_sdt); + }*/ + } +} + +pub enum PossibleAmlTables { + Dsdt(Dsdt), + Ssdt(Ssdt), +} +impl PossibleAmlTables { + pub fn try_new(inner: Sdt) -> Option { + match &inner.signature { + b"DSDT" => Some(Self::Dsdt(Dsdt(inner))), + b"SSDT" => Some(Self::Ssdt(Ssdt(inner))), + _ => None, + } + } +} +impl AmlContainingTable for PossibleAmlTables { + fn aml(&self) -> &[u8] { + match self { + Self::Dsdt(dsdt) => dsdt.aml(), + Self::Ssdt(ssdt) => ssdt.aml(), + } + } +} + +pub trait AmlContainingTable { + fn aml(&self) -> &[u8]; +} + +impl AmlContainingTable for &T +where + T: AmlContainingTable, +{ + fn aml(&self) -> &[u8] { + T::aml(*self) + } +} + +impl AmlContainingTable for Dsdt { + fn aml(&self) -> &[u8] { + self.0.data() + } +} +impl AmlContainingTable for Ssdt { + fn aml(&self) -> &[u8] { + self.0.data() + } +} diff --git a/acpid/src/aml/dataobj.rs b/acpid/src/aml/dataobj.rs new file mode 100644 index 0000000000..6e4ab1da73 --- /dev/null +++ b/acpid/src/aml/dataobj.rs @@ -0,0 +1,184 @@ +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/acpid/src/aml/mod.rs b/acpid/src/aml/mod.rs new file mode 100644 index 0000000000..903597afe2 --- /dev/null +++ b/acpid/src/aml/mod.rs @@ -0,0 +1,141 @@ +//! # AML +//! +//! Code to parse and execute ACPI Machine Language tables. + +use std::collections::HashMap; + +use syscall::io::{Io, Pio}; + +use crate::acpi::{AcpiContext, AmlContainingTable, Sdt, SdtHeader}; + +#[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: impl AmlContainingTable) -> Result, AmlError> { + parse_aml_with_scope(sdt, "\\".to_owned()) +} + +pub fn parse_aml_with_scope(sdt: impl AmlContainingTable, scope: String) -> Result, AmlError> { + let data = sdt.aml(); + let mut ctx = AmlExecutionContext::new(scope); + + parse_term_list(data, &mut ctx)?; + + Ok(ctx.namespace_delta) +} + +pub fn is_aml_table(sdt: &SdtHeader) -> bool { + if &sdt.signature == b"DSDT" || &sdt.signature == b"SSDT" { + true + } else { + false + } +} + +fn init_aml_table(sdt: impl AmlContainingTable) { + 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"); + // TODO + return; + }, + Err(AmlError::AmlHardFatal) => { + println!(": Fatal error occurred"); + // TODO + return; + } + } +} +fn init_namespace(context: &AcpiContext) -> HashMap { + let dsdt = context.dsdt().expect("could not find any DSDT"); + + log::info!("Found DSDT."); + init_aml_table(dsdt); + + let ssdts = context.ssdts(); + + for ssdt in ssdts { + print!("Found SSDT."); + init_aml_table(ssdt); + } + + todo!() +} + +pub fn set_global_s_state(context: &AcpiContext, state: u8) { + if state != 5 { + return + } + let fadt = match context.fadt() { + Some(fadt) => fadt, + None => { + log::error!("Cannot set global S-state due to missing FADT."); + return; + } + }; + + let port = fadt.pm1a_control_block as u16; + let mut val = 1 << 13; + + let namespace = match context.namespace() { + Some(namespace) => namespace, + None => { + log::error!("Cannot set global S-state due to missing ACPI namespace"); + return; + } + }; + + let s5 = match namespace.get("\\_S5") { + Some(s5) => s5, + None => { + log::error!("Cannot set global S-state due to missing \\_S5"); + return; + } + }; + let p = match s5.get_as_package() { + Ok(package) => package, + Err(error) => { + log::error!("Cannot set global S-state due to \\_S5 not being a package: {:?}", error); + return; + } + }; + + 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"); + + log::info!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); + val |= slp_typa as u16; + + log::info!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); + Pio::::new(port).write(val); +} diff --git a/acpid/src/aml/namedobj.rs b/acpid/src/aml/namedobj.rs new file mode 100644 index 0000000000..01e272e492 --- /dev/null +++ b/acpid/src/aml/namedobj.rs @@ -0,0 +1,1043 @@ +use std::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(ctx.acpi_context(), 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/acpid/src/aml/namespace.rs b/acpid/src/aml/namespace.rs new file mode 100644 index 0000000000..9b3e12b2ba --- /dev/null +++ b/acpid/src/aml/namespace.rs @@ -0,0 +1,486 @@ +use std::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::{AcpiContext, SdtSignature}; + +#[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, acpi_ctx: &AcpiContext) -> Result<(Vec, SdtSignature), AmlError> { + match *self { + AmlValue::DDBHandle(ref v) => Ok(v.clone()), + AmlValue::Integer(i) => if let Some(sig) = acpi_ctx.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, acpi_ctx: &AcpiContext) -> 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) = acpi_ctx.get_index_from_signature(&v.1) { + 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/acpid/src/aml/namespacemodifier.rs b/acpid/src/aml/namespacemodifier.rs new file mode 100644 index 0000000000..77fa1406b0 --- /dev/null +++ b/acpid/src/aml/namespacemodifier.rs @@ -0,0 +1,106 @@ +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/acpid/src/aml/namestring.rs b/acpid/src/aml/namestring.rs new file mode 100644 index 0000000000..dd3eb88a33 --- /dev/null +++ b/acpid/src/aml/namestring.rs @@ -0,0 +1,223 @@ +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/acpid/src/aml/parser.rs b/acpid/src/aml/parser.rs new file mode 100644 index 0000000000..aff1aaa158 --- /dev/null +++ b/acpid/src/aml/parser.rs @@ -0,0 +1,559 @@ +use std::string::String; +use std::collections::BTreeMap; +use std::vec::Vec; +use std::boxed::Box; + +use parking_lot::RwLockWriteGuard; + +use super::namespace::{AmlValue, ObjectReference}; +use super::AmlError; + +use crate::acpi::AcpiContext; + +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<'a> { + 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, + + pub acpi_context: &'a AcpiContext, +} + +impl<'a> AmlExecutionContext<'a> { + pub fn new(acpi_context: &'a AcpiContext, 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, + + acpi_context, + } + } + pub fn acpi_context(&self) -> &'a AcpiContext { + self.acpi_context + } + + 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/acpid/src/aml/parsermacros.rs b/acpid/src/aml/parsermacros.rs new file mode 100644 index 0000000000..31a23386ff --- /dev/null +++ b/acpid/src/aml/parsermacros.rs @@ -0,0 +1,52 @@ +#[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/acpid/src/aml/pkglength.rs b/acpid/src/aml/pkglength.rs new file mode 100644 index 0000000000..7b511f9b44 --- /dev/null +++ b/acpid/src/aml/pkglength.rs @@ -0,0 +1,25 @@ +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/acpid/src/aml/termlist.rs b/acpid/src/aml/termlist.rs new file mode 100644 index 0000000000..c382a7c5c0 --- /dev/null +++ b/acpid/src/aml/termlist.rs @@ -0,0 +1,172 @@ +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/acpid/src/aml/type1opcode.rs b/acpid/src/aml/type1opcode.rs new file mode 100644 index 0000000000..fe5b8256ba --- /dev/null +++ b/acpid/src/aml/type1opcode.rs @@ -0,0 +1,479 @@ +use std::mem; + +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::monotonic; + +use crate::acpi::{PossibleAmlTables, SdtHeader}; +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()?; + // TODO + let sdt = plain::from_bytes::(&tbl[..mem::size_of::()]).unwrap(); + + let table = match ctx.acpi_context().sdt_from_signature(&sdt.signature()) { + Some(table) => table, + None => return Err(AmlError::AmlValueError), + }; + + if let Some(aml_sdt) = PossibleAmlTables::try_new(table.clone()) { + let delta = parse_aml_table(aml_sdt)?; + let _ = ctx.modify(ddb_handle_object.val, AmlValue::DDBHandle((delta, sdt.signature()))); + + 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/acpid/src/aml/type2opcode.rs b/acpid/src/aml/type2opcode.rs new file mode 100644 index 0000000000..846d44a658 --- /dev/null +++ b/acpid/src/aml/type2opcode.rs @@ -0,0 +1,1784 @@ +use std::convert::TryFrom; + +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::monotonic; +use crate::acpi::{PossibleAmlTables, SdtSignature}; + +#[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: How long should be sleep be? + let _ = syscall::sched_yield(); + } 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 { + let _ = syscall::sched_yield(); + } else { + let (seconds, nanoseconds) = crate::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)?; + + let signature = { + <[u8; 4]>::try_from(&*signature.val.get_as_buffer()?) + .expect("expected 'load table' def to have a signature that is 4 bytes long") + }; + let oem_id = { + <[u8; 6]>::try_from(&*oem_id.val.get_as_buffer()?) + .expect("expected 'load table' def to have an OEM ID that is 6 bytes long") + }; + let oem_table_id = { + <[u8; 8]>::try_from(&*oem_table_id.val.get_as_buffer()?) + .expect("expected 'load table' def to have an OEM table ID that is 8 bytes long") + }; + + let sdt_signature = SdtSignature { + signature, + oem_id, + oem_table_id, + }; + + let parse_len = 2 + signature.len() + oem_id.len() + oem_table_id.len() + root_path.len + parameter_path.len + parameter_data.len; + + let sdt = ctx.acpi_context().sdt_from_signature(&sdt_signature); + + Ok(if let Some(sdt) = sdt.and_then(|sdt| PossibleAmlTables::try_new(sdt.clone())) { + let hdl = parse_aml_with_scope(sdt, root_path.val.get_as_string()?)?; + let _ = ctx.modify(parameter_path.val, parameter_data.val); + + AmlParseType { + val: AmlValue::DDBHandle((hdl, sdt_signature)), + len: parse_len, + } + } else { + AmlParseType { + val: AmlValue::IntegerConstant(0), + len: parse_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); + } + + 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/acpid/src/main.rs b/acpid/src/main.rs new file mode 100644 index 0000000000..54ebe96d1b --- /dev/null +++ b/acpid/src/main.rs @@ -0,0 +1,55 @@ +use std::convert::TryFrom; +use std::mem; +use std::sync::Arc; + +mod acpi; +mod aml; + +// TODO: Perhaps use the acpi and aml crates? + +fn monotonic() -> (u64, u64) { + use syscall::call::clock_gettime; + use syscall::data::TimeSpec; + use syscall::flag::CLOCK_MONOTONIC; + + let mut timespec = TimeSpec::default(); + + clock_gettime(CLOCK_MONOTONIC, &mut timespec) + .expect("failed to fetch monotonic time"); + + (timespec.tv_sec as u64, timespec.tv_nsec as u64) +} + + +fn main() { + let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel/acpi:") + .expect("acpid: failed to read `kernel/acpi:`") + .into(); + + let sdt = self::acpi::Sdt::new(rxsdt_raw_data) + .expect("acpid: failed to parse [RX]SDT"); + + let mut thirty_two_bit; + let mut sixty_four_bit; + + let physaddrs_iter = match &sdt.signature { + b"RSDT" => { + thirty_two_bit = sdt.data().chunks(mem::size_of::()) + // TODO: With const generics, the compiler has some way of doing this for static sizes. + .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) + .map(|chunk| u32::from_le_bytes(chunk)) + .map(u64::from); + + &mut thirty_two_bit as &mut dyn Iterator + } + b"XSDT" => { + sixty_four_bit = sdt.data().chunks(mem::size_of::()) + .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) + .map(|chunk| u64::from_le_bytes(chunk)); + + &mut sixty_four_bit as &mut dyn Iterator + }, + _ => panic!("acpid: expected [RX]SDT from kernel to be either of those"), + }; + +} diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 60e0701750..b16f7cf456 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -72,8 +72,8 @@ impl DisplayScheme { } impl SchemeMut for DisplayScheme { - fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - if path == b"input" { + fn open(&mut self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { + if path_str == "input" { if uid == 0 { let id = self.next_id; self.next_id += 1; @@ -90,7 +90,6 @@ impl SchemeMut for DisplayScheme { Err(Error::new(EACCES)) } } else { - let path_str = str::from_utf8(path).unwrap_or("").trim_matches('/'); let mut parts = path_str.split('/'); let screen_i = parts.next().unwrap_or("").parse::().unwrap_or(0); if self.screens.contains_key(&screen_i) {