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