Merge branch 'master' into fix_warnings

This commit is contained in:
bjorn3
2017-06-26 14:22:17 +02:00
committed by GitHub
33 changed files with 3396 additions and 225 deletions

View File

@@ -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
View File

@@ -0,0 +1,3 @@
[dependencies.alloc]
[dependencies.collections]

View File

@@ -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
View 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
View 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
View 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
View 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!()));
}
}

View 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
View 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)
}
}
}

View 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
View 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
View 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
View 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
View 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))
}

View File

@@ -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))
}
}

View File

@@ -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)]

View File

@@ -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()) }
}
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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
}
}
}

View File

@@ -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
View 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!("");
}
}
}
}
}
}
}

View File

@@ -7,6 +7,7 @@
#![feature(alloc)]
#![feature(asm)]
#![feature(collections)]
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(drop_types_in_const)]

View File

@@ -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)
};

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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))
}
}
}

View File

@@ -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],

View File

@@ -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)
}
}

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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
);