WIP: Move ACPI code from kernel to drivers.
This commit is contained in:
Generated
+72
-12
@@ -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)" = "<none>"
|
||||
"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)" = "<none>"
|
||||
"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)" = "<none>"
|
||||
"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)" = "<none>"
|
||||
"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)" = "<none>"
|
||||
"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"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"acpid",
|
||||
"ahcid",
|
||||
"alxd",
|
||||
"bgad",
|
||||
|
||||
@@ -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"
|
||||
@@ -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<Self> {
|
||||
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<Self, InvalidSdtError> {
|
||||
let header = match plain::from_bytes::<SdtHeader>(&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<Self, TablePhysLoadError> {
|
||||
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::<SdtHeader>()).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::<SdtHeader>());
|
||||
let sdt_mem = &pages[physaddr_page_offset..];
|
||||
|
||||
let sdt = plain::from_bytes::<SdtHeader>(&pages[mem::size_of::<SdtHeader>()..])
|
||||
.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::<SdtHeader>(&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::<SdtHeader>()..]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Dsdt(Sdt);
|
||||
pub struct Ssdt(Sdt);
|
||||
|
||||
pub struct AcpiContext {
|
||||
tables: Vec<Sdt>,
|
||||
dsdt: Option<Dsdt>,
|
||||
fadt: Option<Fadt>,
|
||||
namespace: Option<HashMap<String, AmlValue>>,
|
||||
}
|
||||
impl AcpiContext {
|
||||
pub fn dsdt(&self) -> Option<&Dsdt> {
|
||||
self.dsdt.as_ref()
|
||||
}
|
||||
pub fn ssdts(&self) -> impl Iterator<Item = Ssdt> + '_ {
|
||||
self.find_multiple_sdts(*b"SSDT").map(|sdt| Ssdt(sdt.clone()))
|
||||
}
|
||||
fn find_single_sdt_pos(&self, signature: [u8; 4]) -> Option<usize> {
|
||||
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<Item = &'a Sdt> {
|
||||
self.tables.iter().filter(move |sdt| sdt.signature == signature)
|
||||
}
|
||||
pub fn take_single_sdt(&mut self, signature: [u8; 4]) -> Option<Sdt> {
|
||||
self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone())
|
||||
}
|
||||
pub fn namespace(&self) -> Option<&HashMap<String, AmlValue>> {
|
||||
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<SdtSignature> {
|
||||
todo!()
|
||||
}
|
||||
pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option<usize> {
|
||||
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::<FadtStruct>()..];
|
||||
|
||||
match plain::from_bytes::<FadtAcpi2Struct>(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::<FadtStruct>(&self.0.0)
|
||||
.expect("expected FADT struct to already be validated in Deref impl")
|
||||
}
|
||||
}
|
||||
|
||||
impl Fadt {
|
||||
pub fn new(context: &AcpiContext, sdt: Sdt) -> Option<Fadt> {
|
||||
if sdt.signature != *b"FACP" || sdt.length() < mem::size_of::<Fadt>() {
|
||||
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<Self> {
|
||||
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<T> 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()
|
||||
}
|
||||
}
|
||||
@@ -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<u8> = 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)
|
||||
}
|
||||
}
|
||||
@@ -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<Vec<String>, AmlError> {
|
||||
parse_aml_with_scope(sdt, "\\".to_owned())
|
||||
}
|
||||
|
||||
pub fn parse_aml_with_scope(sdt: impl AmlContainingTable, scope: String) -> Result<Vec<String>, 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<String, AmlValue> {
|
||||
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::<u16>::new(port).write(val);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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<AmlValue>
|
||||
},
|
||||
Index {
|
||||
index_selector: String,
|
||||
data_selector: String
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ObjectReference {
|
||||
ArgObj(u8),
|
||||
LocalObj(u8),
|
||||
Object(String),
|
||||
Index(Box<AmlValue>, Box<AmlValue>)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Method {
|
||||
pub arg_count: u8,
|
||||
pub serialized: bool,
|
||||
pub sync_level: u8,
|
||||
pub term_list: Vec<u8>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BufferField {
|
||||
pub source_buf: Box<AmlValue>,
|
||||
pub index: Box<AmlValue>,
|
||||
pub length: Box<AmlValue>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FieldUnit {
|
||||
pub selector: FieldSelector,
|
||||
pub connection: Box<AmlValue>,
|
||||
pub flags: FieldFlags,
|
||||
pub offset: usize,
|
||||
pub length: usize
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Device {
|
||||
pub obj_list: Vec<String>,
|
||||
pub notify_methods: BTreeMap<u8, Vec<fn()>>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ThermalZone {
|
||||
pub obj_list: Vec<String>,
|
||||
pub notify_methods: BTreeMap<u8, Vec<fn()>>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Processor {
|
||||
pub proc_id: u8,
|
||||
pub p_blk: Option<u32>,
|
||||
pub obj_list: Vec<String>,
|
||||
pub notify_methods: BTreeMap<u8, Vec<fn()>>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OperationRegion {
|
||||
pub region: RegionSpace,
|
||||
pub offset: Box<AmlValue>,
|
||||
pub len: Box<AmlValue>,
|
||||
pub accessor: Accessor,
|
||||
pub accessed_by: Option<u64>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PowerResource {
|
||||
pub system_level: u8,
|
||||
pub resource_order: u16,
|
||||
pub obj_list: Vec<String>
|
||||
}
|
||||
|
||||
#[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<u8>),
|
||||
BufferField(BufferField),
|
||||
DDBHandle((Vec<String>, SdtSignature)),
|
||||
DebugObject,
|
||||
Device(Device),
|
||||
Event(u64),
|
||||
FieldUnit(FieldUnit),
|
||||
Integer(u64),
|
||||
IntegerConstant(u64),
|
||||
Method(Method),
|
||||
Mutex((u8, Option<u64>)),
|
||||
ObjectReference(ObjectReference),
|
||||
OperationRegion(OperationRegion),
|
||||
Package(Vec<AmlValue>),
|
||||
String(String),
|
||||
PowerResource(PowerResource),
|
||||
Processor(Processor),
|
||||
RawDataBuffer(Vec<u8>),
|
||||
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<AmlValue, AmlError> {
|
||||
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<Vec<u8>, AmlError> {
|
||||
match *self {
|
||||
AmlValue::Buffer(ref b) => Ok(b.clone()),
|
||||
AmlValue::Integer(ref i) => {
|
||||
let mut v: Vec<u8> = 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<BufferField, AmlError> {
|
||||
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<String>, 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<Device, AmlError> {
|
||||
match *self {
|
||||
AmlValue::Device(ref s) => Ok(s.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_event(&self) -> Result<u64, AmlError> {
|
||||
match *self {
|
||||
AmlValue::Event(ref e) => Ok(e.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_field_unit(&self) -> Result<FieldUnit, AmlError> {
|
||||
match *self {
|
||||
AmlValue::FieldUnit(ref e) => Ok(e.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_integer(&self, acpi_ctx: &AcpiContext) -> Result<u64, AmlError> {
|
||||
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<u64, AmlError> {
|
||||
match *self {
|
||||
AmlValue::IntegerConstant(ref i) => Ok(i.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_method(&self) -> Result<Method, AmlError> {
|
||||
match *self {
|
||||
AmlValue::Method(ref m) => Ok(m.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_mutex(&self) -> Result<(u8, Option<u64>), AmlError> {
|
||||
match *self {
|
||||
AmlValue::Mutex(ref m) => Ok(m.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_object_reference(&self) -> Result<ObjectReference, AmlError> {
|
||||
match *self {
|
||||
AmlValue::ObjectReference(ref m) => Ok(m.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn get_as_operation_region(&self) -> Result<OperationRegion, AmlError> {
|
||||
match *self {
|
||||
AmlValue::OperationRegion(ref p) => Ok(p.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn get_as_package(&self) -> Result<Vec<AmlValue>, AmlError> {
|
||||
match *self {
|
||||
AmlValue::Package(ref p) => Ok(p.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_string(&self) -> Result<String, AmlError> {
|
||||
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<PowerResource, AmlError> {
|
||||
match *self {
|
||||
AmlValue::PowerResource(ref p) => Ok(p.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_processor(&self) -> Result<Processor, AmlError> {
|
||||
match *self {
|
||||
AmlValue::Processor(ref p) => Ok(p.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_raw_data_buffer(&self) -> Result<Vec<u8>, AmlError> {
|
||||
match *self {
|
||||
AmlValue::RawDataBuffer(ref p) => Ok(p.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_as_thermal_zone(&self) -> Result<ThermalZone, AmlError> {
|
||||
match *self {
|
||||
AmlValue::ThermalZone(ref p) => Ok(p.clone()),
|
||||
_ => Err(AmlError::AmlValueError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Method {
|
||||
pub fn execute(&self, scope: String, parameters: Vec<AmlValue>) -> 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<String, AmlError> {
|
||||
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)
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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<u8> = 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<u8>, usize), AmlError> {
|
||||
parser_opcode!(data, 0x00);
|
||||
Ok((vec!(), 1 ))
|
||||
}
|
||||
|
||||
pub fn parse_name_seg(data: &[u8]) -> Result<(Vec<u8>, 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<u8>, usize), AmlError> {
|
||||
parser_opcode!(data, 0x2E);
|
||||
|
||||
let mut characters: Vec<u8> = 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<u8>, 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<u8> = 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)
|
||||
}
|
||||
}
|
||||
@@ -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<AmlParseType, AmlError>;
|
||||
pub type AmlParseType = AmlParseTypeGeneric<AmlValue>;
|
||||
|
||||
pub struct AmlParseTypeGeneric<T> {
|
||||
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<String>,
|
||||
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<bool, 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) => {
|
||||
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<bool, 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 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<AmlValue>) {
|
||||
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<BTreeMap<String, AmlValue>>> {
|
||||
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<u64>) -> 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<u64>) -> Result<AmlValue, AmlError> {
|
||||
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<u64>) -> 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<u64>) -> Result<AmlValue, AmlError> {
|
||||
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<u64>) -> Result<AmlValue, AmlError> {
|
||||
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<u64>) -> Result<AmlValue, AmlError>{
|
||||
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<AmlValue, AmlError> {
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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<AmlValue> = 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)
|
||||
}
|
||||
@@ -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::<SdtHeader>(&tbl[..mem::size_of::<SdtHeader>()]).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
|
||||
})
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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::<u32>())
|
||||
// TODO: With const generics, the compiler has some way of doing this for static sizes.
|
||||
.map(|chunk| <[u8; mem::size_of::<u32>()]>::try_from(chunk).unwrap())
|
||||
.map(|chunk| u32::from_le_bytes(chunk))
|
||||
.map(u64::from);
|
||||
|
||||
&mut thirty_two_bit as &mut dyn Iterator<Item = u64>
|
||||
}
|
||||
b"XSDT" => {
|
||||
sixty_four_bit = sdt.data().chunks(mem::size_of::<u64>())
|
||||
.map(|chunk| <[u8; mem::size_of::<u64>()]>::try_from(chunk).unwrap())
|
||||
.map(|chunk| u64::from_le_bytes(chunk));
|
||||
|
||||
&mut sixty_four_bit as &mut dyn Iterator<Item = u64>
|
||||
},
|
||||
_ => panic!("acpid: expected [RX]SDT from kernel to be either of those"),
|
||||
};
|
||||
|
||||
}
|
||||
+2
-3
@@ -72,8 +72,8 @@ impl DisplayScheme {
|
||||
}
|
||||
|
||||
impl SchemeMut for DisplayScheme {
|
||||
fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||
if path == b"input" {
|
||||
fn open(&mut self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||
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::<usize>().unwrap_or(0);
|
||||
if self.screens.contains_key(&screen_i) {
|
||||
|
||||
Reference in New Issue
Block a user