WIP: Move ACPI code from kernel to drivers.

This commit is contained in:
4lDO2
2021-03-10 11:24:27 +01:00
parent 00b7674321
commit be984885bb
18 changed files with 5841 additions and 15 deletions
Generated
+72 -12
View File
@@ -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
View File
@@ -1,5 +1,6 @@
[workspace]
members = [
"acpid",
"ahcid",
"alxd",
"bgad",
+14
View File
@@ -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"
+443
View File
@@ -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()
}
}
+184
View File
@@ -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)
}
}
+141
View File
@@ -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
+486
View File
@@ -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)
}
+106
View File
@@ -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
})
}
+223
View File
@@ -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)
}
}
+559
View File
@@ -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
})
}
}
+52
View File
@@ -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);
}
};
}
+25
View File
@@ -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))
}
+172
View File
@@ -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)
}
+479
View File
@@ -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
+55
View File
@@ -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
View File
@@ -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) {