シャットダウンの実装
by だいみょーじん
目次
2
自己紹介
3
前回のおさらい
4
前回のおさらい
5
実行環境 | EFI_RESET_SYSTEM関数によるシャットダウン |
QEMU | 成功 |
VirtualBox | 失敗 |
VMware | 成功 |
GPC MicroPC | 成功 |
前回のおさらい
6
電源状態 | CPUの命令の実行 | CPUのレジスタ | 主記憶 |
S0 | 実行 | 保持 | 保持 |
S1 | 停止 | 保持 | 保持 |
S2 | 停止 | 破棄 | 保持 |
S3 | 停止 | 破棄 | 保持 |
S4 | 停止 | 破棄 | 補助記憶に退避 |
S5 | 停止 | 破棄 | 破棄 |
ACPIの仕様書の7.4.2で定義されている電源状態
前回のおさらい
7
AMLで記述されたDSDT
前回のおさらい
8
前回のおさらい
9
ACPIの仕様書の7.5の図7.1
前回のおさらい
10
DSDT
DSDT構文木
構文解析
今回やること
11
構文木の地図を作る
12
構文木の地図を作る
13
_SBの直下にBN00ないんだけど...
実はここにある.
_SB.PCI0.^BN00=_SB.BN00
_SB.BN00どこー?
AMLインタプリタ
ASL(ACPI Source Language)
構文木の地図を作る
14
構文木の地図を作る
15
// 参照木を構成するノード
pub struct Node<'a> {
name: name::Segment,
objects: Vec<Object<'a>>,
children: Vec<Self>,
}
// 構文木の部分木への参照
pub enum Object<'a> {
Alias(&'a syntax::DefAlias),
CreateBitField(&'a syntax::DefCreateBitField),
CreateByteField(&'a syntax::DefCreateByteField),
CreateDWordField(&'a syntax::DefCreateDWordField),
CreateField(&'a syntax::DefCreateField),
CreateQWordField(&'a syntax::DefCreateQWordField),
CreateWordField(&'a syntax::DefCreateWordField),
DataRegion(&'a syntax::DefDataRegion),
Device(&'a syntax::DefDevice),
Event(&'a syntax::DefEvent),
External(&'a syntax::DefExternal),
Load(&'a syntax::DefLoad),
Method(&'a syntax::DefMethod),
Mutex(&'a syntax::DefMutex),
Name(&'a syntax::DefName),
...
}
AMLのデータ型
16
pub enum Value {
Bool(bool),
Byte(u8),
Word(u16),
DWord(u32),
QWord(u64),
Zero,
One,
Ones,
Char(char),
String(String),
Buffer(Vec<u8>),
Package(Vec<Self>),
}
キャストを実装したり...
17
fn match_type(&self, other: &Self) -> (Self, Self) {
match (self, other) {
(Self::Bool(left), Self::Bool(right)) => (Self::Bool(*left), Self::Bool(*right)),
(Self::Buffer(left), Self::Buffer(right)) => (Self::Buffer(left.clone()), Self::Buffer(right.clone())),
(Self::Buffer(left), Self::String(right)) => {
let right: Vec<u8> = right
.bytes()
.chain(iter::repeat(0x00))
.take(left.len())
.collect();
(Self::Buffer(left.clone()), Self::Buffer(right))
},
(Self::Byte(left), Self::Byte(right)) => (Self::Byte(*left), Self::Byte(*right)),
(Self::Byte(left), Self::DWord(right)) => (Self::DWord(*left as u32), Self::DWord(*right)),
(Self::Byte(left), Self::One) => (Self::Byte(*left), Self::Byte(0x01)),
(Self::Byte(left), Self::Ones) => (Self::Byte(*left), Self::Byte(0xff)),
(Self::Byte(left), Self::QWord(right)) => (Self::QWord(*left as u64), Self::QWord(*right)),
(Self::Byte(left), Self::Word(right)) => (Self::Word(*left as u16), Self::Word(*right)),
(Self::Byte(left), Self::Zero) => (Self::Byte(*left), Self::Byte(0x00)),
(Self::Char(left), Self::Char(right)) => (Self::Char(*left), Self::Char(*right)),
(Self::DWord(left), Self::Byte(right)) => (Self::DWord(*left), Self::DWord(*right as u32)),
(Self::DWord(left), Self::DWord(right)) => (Self::DWord(*left), Self::DWord(*right)),
…以下略
足し算を実装したり...
18
impl Add for Value {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
match self.match_type(&other) {
(Self::Byte(left), Self::Byte(right)) => Self::Output::Byte(left + right),
(Self::Word(left), Self::Word(right)) => Self::Output::Word(left + right),
(Self::DWord(left), Self::DWord(right)) => Self::Output::DWord(left + right),
(Self::QWord(left), Self::QWord(right)) => Self::Output::QWord(left + right),
(Self::Zero, Self::Zero) => Self::Output::Zero,
(Self::Zero, Self::One) => Self::Output::One,
(Self::Zero, Self::Ones) => Self::Output::Ones,
(Self::One, Self::Zero) => Self::Output::One,
(Self::One, Self::One) => Self::Output::QWord(1 + 1),
(Self::Ones, Self::Zero) => Self::Output::Ones,
(left, right) => unimplemented!("left = {:#x?}, right = {:#x?}", left, right),
}
}
}
排他的論理和のビット演算を実装したり...
19
impl BitXor for Value {
type Output = Self;
fn bitxor(self, other: Self) -> Self::Output {
match self.match_type(&other) {
(Self::Byte(left), Self::Byte(right)) => Self::Output::Byte(left ^ right),
(Self::Word(left), Self::Word(right)) => Self::Output::Word(left ^ right),
(Self::DWord(left), Self::DWord(right)) => Self::Output::DWord(left ^ right),
(Self::QWord(left), Self::QWord(right)) => Self::Output::QWord(left ^ right),
(Self::Zero, Self::Zero) => Self::Output::Zero,
(Self::Zero, Self::One) => Self::Output::One,
(Self::Zero, Self::Ones) => Self::Output::Ones,
(Self::One, Self::Zero) => Self::Output::One,
(Self::One, Self::One) => Self::Output::Zero,
(Self::One, Self::Ones) => Self::Output::QWord(1 ^ u64::MAX),
(Self::Ones, Self::Zero) => Self::Output::Ones,
(Self::Ones, Self::One) => Self::Output::QWord(u64::MAX ^ 1),
(Self::Ones, Self::Ones) => Self::Output::Zero,
(left, right) => unimplemented!("left = {:#x?}, right = {:#x?}", left, right),
}
}
}
AMLのスタックフレーム
20
pub struct StackFrame {
arguments: [Option<Value>; 0x07],
locals: [Option<Value>; 0x08],
named_locals: BTreeMap<name::Path, Value>,
return_value: Option<Value>,
broken: Vec<bool>,
continued: Vec<bool>,
}
Evaluatorトレイト
21
pub trait Evaluator {
fn evaluate(&self, stack_frame: &mut StackFrame, root: &reference::Node, current: &name::Path) -> Option<Value>;
}
Evaluatorトレイトの実装例
22
pub struct ByteData(u8);
impl Evaluator for ByteData {
fn evaluate(&self, _stack_frame: &mut interpreter::StackFrame, _root: &reference::Node, _current: &name::Path) -> Option<interpreter::Value> {
let Self(byte) = self;
Some(interpreter::Value::Byte(*byte))
}
}
pub struct ByteList(Vec<ByteData>);
impl Evaluator for ByteList {
fn evaluate(&self, stack_frame: &mut interpreter::StackFrame, root: &reference::Node, current: &name::Path) -> Option<interpreter::Value> {
let Self(byte_list) = self;
Some(interpreter::Value::Buffer(byte_list
.iter()
.filter_map(|byte_data| byte_data
.evaluate(stack_frame, root, current)
.and_then(|byte_data| byte_data.get_byte()))
.collect()))
}
}
Evaluatorトレイトの実装例
23
pub struct DefLEqual(
LEqualOp,
[Operand; 2],
);
impl Evaluator for DefLEqual {
fn evaluate(&self, stack_frame: &mut interpreter::StackFrame, root: &reference::Node, current: &name::Path) -> Option<interpreter::Value> {
let Self(
_l_equal_op,
[left, right],
) = self;
let left: Option<interpreter::Value> = left.evaluate(stack_frame, root, current);
let right: Option<interpreter::Value> = right.evaluate(stack_frame, root, current);
left
.zip(right)
.map(|(left, right)| interpreter::Value::Bool(left == right))
}
}
Evaluatorトレイトの実装例
24
pub struct TermList(
Vec<TermObj>,
);
impl Evaluator for TermList {
fn evaluate(&self, stack_frame: &mut interpreter::StackFrame, root: &reference::Node, current: &name::Path) -> Option<interpreter::Value> {
let Self(term_objs) = self;
term_objs
.iter()
.for_each(|term_obj| if stack_frame.read_return().is_none() && !stack_frame.is_broken() && !stack_frame.is_continued() {
term_obj.evaluate(stack_frame, root, current);
});
stack_frame
.read_return()
.cloned()
}
}
代入
25
pub struct DefStore(
StoreOp,
TermArg,
SuperName,
);
impl Evaluator for DefStore {
fn evaluate(&self, stack_frame: &mut interpreter::StackFrame, root: &reference::Node, current: &name::Path) -> Option<interpreter::Value> {
let Self(
_store_op,
term_arg,
super_name,
) = self;
term_arg
.evaluate(stack_frame, root, current)
.map(|term_arg| super_name.hold(term_arg, stack_frame, root, current))
}
}
Holderトレイト
26
pub trait Holder {
fn hold(&self, value: Value, stack_frame: &mut StackFrame, root: &reference::Node, current: &name::Path) -> Value;
}
Holderトレイトの実装例
27
pub struct LocalObj(u8);
impl Holder for LocalObj {
fn hold(&self, value: interpreter::Value, stack_frame: &mut interpreter::StackFrame, _root: &reference::Node, _current: &name::Path) -> interpreter::Value {
let Self(index) = self;
stack_frame.write_local(*index as usize, value)
}
}
impl StackFrame {
...
pub fn write_local(&mut self, index: usize, value: Value) -> Value {
self.locals[index] = Some(value.clone());
value
}
...
}
NamedFieldへの代入
28
OperationRegion (DBG0, SystemIO, 0x3000, 0x04)
Field (DBG0, ByteAcc, NoLock, Preserve)
{
DHE1, 8
}
if-else文
29
pub struct DefIfElse(
DefIf,
Option<DefElse>,
);
impl Evaluator for DefIfElse {
fn evaluate(&self, stack_frame: &mut interpreter::StackFrame, root: &reference::Node, current: &name::Path) -> Option<interpreter::Value> {
let Self(
DefIf(
_if_op,
_pkg_length,
predicate,
term_list,
),
def_else,
) = self;
if predicate
.evaluate(stack_frame, root, current)
.map_or(false, |predicate| (&predicate).into()) {
term_list.evaluate(stack_frame, root, current)
} else {
def_else
.as_ref()
.and_then(|def_else| def_else.evaluate(stack_frame, root, current))
}
}
}
while文
30
impl Evaluator for DefWhile {
fn evaluate(&self, stack_frame: &mut interpreter::StackFrame, root: &reference::Node, current: &name::Path) -> Option<interpreter::Value> {
let Self(
_while_op,
_pkg_length,
predicate,
term_list,
) = self;
stack_frame.enter_loop();
while {
let predicate: bool = predicate
.evaluate(stack_frame, root, current)
.map_or(false, |predicate| (&predicate).into());
let broken: bool = stack_frame.is_broken();
predicate && !broken
} {
term_list.evaluate(stack_frame, root, current);
stack_frame.uncontinue();
}
stack_frame.leave_loop();
None
}
}
pub struct DefWhile(
WhileOp,
PkgLength,
Predicate,
TermList,
);
関数呼び出し
31
impl Evaluator for MethodInvocation {
fn evaluate(&self, stack_frame: &mut interpreter::StackFrame, root: &reference::Node, current: &name::Path) -> Option<interpreter::Value> {
let Self(
name_string,
term_args,
) = self;
let relative_method_path: name::Path = name_string.into(); // 関数の相対パス
let absolute_method_path = name::AbsolutePath::new(current, &relative_method_path); // 関数の絶対パス
let term_args: Vec<interpreter::Value> = term_args // 関数に渡す引数を評価
.iter()
.filter_map(|term_arg| term_arg.evaluate(stack_frame, root, current))
.collect();
stack_frame
.read_named_local(&relative_method_path) // 名前付きローカル変数だった場合,その値を返す.
.or_else(|| root
.get_name_from_current(&absolute_method_path) // 名前付きグローバル変数名だった場合,その値を返す.
.and_then(|(current, name)| name.evaluate(stack_frame, root, ¤t)))
.or_else(|| root.read_named_field(stack_frame, root, &absolute_method_path)) // NamedFieldだった場合,そこから値を読みだす.
.or_else(|| root
.get_method_from_current(&absolute_method_path) // 関数だった場合,その関数を実行し,その返り値を返す.
.and_then(|(current, method)| {
let mut stack_frame = interpreter::StackFrame::default() // 関数を実行するための新しいスタックフレーム
.set_arguments(term_args); // スタックフレームに引数を設定
method.evaluate(&mut stack_frame, root, ¤t) // 関数を実行し,その返り値を返す.
}))
}
}
ついにシャットダウンできるように!
32
まとめ
ご清聴ありがとうございました!
33