1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
aml_compiler.rs 73 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
ace yan Отправлено 3 лет назад 4df5013
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462
// Copyright (c) 2020 Huawei Technologies Co.,Ltd. All rights reserved.
//
// StratoVirt is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
use util::byte_code::ByteCode;
const ACPI_NAME_SEG_MAX: u8 = 4;
/// This trait is used for converting AML Data structure to byte stream.
pub trait AmlBuilder {
/// Transfer this struct to byte stream.
fn aml_bytes(&self) -> Vec<u8>;
}
/// This trait is used for adding children to AML Data structure that represents
/// a scope, such as `AmlDevice`, `AmlScope`.
pub trait AmlScopeBuilder: AmlBuilder {
/// Append a child to this AML scope structure.
///
/// # Arguments
///
/// * `child` - Child that will be appended to the end of this scope.
fn append_child<T: AmlBuilder>(&mut self, child: T);
}
/// Macro that helps to define `AmlZero`, `AmlOne`, `AmlOnes`
///
/// # Arguments
///
/// * `$name` - struct name
/// * `$byte` - corresponding byte of this structure
macro_rules! zero_one_define {
($name: ident, $byte: expr) => {
pub struct $name;
impl AmlBuilder for $name {
fn aml_bytes(&self) -> Vec<u8> {
vec![$byte]
}
}
};
}
zero_one_define!(AmlZero, 0x00);
zero_one_define!(AmlOne, 0x01);
zero_one_define!(AmlOnes, 0xFF);
/// Macro that helps to define `AmlByte`, `AmlWord`, `AmlDWord`, `AmlQWord`.
///
/// # Arguments
///
/// * `$name` - struct name
/// * `$op` - corresponding Opcode of this structure
/// * `$ty` - inner field of this struct.
macro_rules! aml_bytes_type_define {
($name:ident, $op:expr, $ty:tt) => {
pub struct $name(pub $ty);
impl AmlBuilder for $name {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![$op];
bytes.extend(self.0.as_bytes());
bytes
}
}
};
}
aml_bytes_type_define!(AmlByte, 0x0A, u8);
aml_bytes_type_define!(AmlWord, 0x0B, u16);
aml_bytes_type_define!(AmlDWord, 0x0C, u32);
aml_bytes_type_define!(AmlQWord, 0x0E, u64);
/// Integer, max value u64::MAX.
pub struct AmlInteger(pub u64);
impl AmlBuilder for AmlInteger {
fn aml_bytes(&self) -> Vec<u8> {
match self.0 {
0x00 => AmlZero.aml_bytes(),
0x01 => AmlOne.aml_bytes(),
0x02..=0xFF => AmlByte(self.0 as u8).aml_bytes(),
0x100..=0xFFFF => AmlWord(self.0 as u16).aml_bytes(),
0x10000..=0xFFFF_FFFF => AmlDWord(self.0 as u32).aml_bytes(),
_ => AmlQWord(self.0).aml_bytes(),
}
}
}
/// String
pub struct AmlString(pub String);
impl AmlBuilder for AmlString {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x0D];
bytes.extend(self.0.as_bytes().to_vec());
bytes.push(0x0);
bytes
}
}
/// Parse and check a name-segment, and convert it to byte stream.
fn build_name_seg(name: &str) -> Vec<u8> {
if name.len() > usize::from(ACPI_NAME_SEG_MAX) {
panic!("the length of NameSeg is larger than 4.");
}
let mut bytes = name.as_bytes().to_vec();
bytes.extend(vec![b'_'; ACPI_NAME_SEG_MAX as usize - name.len()]);
bytes
}
/// Parse a name-string and convert it to byte stream
fn build_name_string(name: &str) -> Vec<u8> {
let strs = name.split('.').collect::<Vec<&str>>();
if strs.is_empty() || strs.len() > 255 {
panic!("Invalid ACPI name string, length: {}", strs.len());
}
let mut bytes = Vec::new();
// parse the first segment.
let mut first_str = strs[0].to_string();
let mut index = 0;
for (i, ch) in first_str.chars().enumerate() {
if ch == '\\' || ch == '^' {
bytes.push(ch as u8);
} else {
index = i;
break;
}
}
let remain_first = first_str.drain(index..).collect::<String>();
match strs.len() {
1 => {
if remain_first.is_empty() {
bytes.push(0x00);
} else {
bytes.append(&mut build_name_seg(&remain_first));
}
}
2 => {
bytes.push(0x2E);
bytes.append(&mut build_name_seg(&remain_first));
bytes.append(&mut build_name_seg(strs[1]));
}
_ => {
bytes.push(0x2F);
bytes.push(strs.len() as u8);
bytes.append(&mut build_name_seg(&remain_first));
strs.iter().skip(1).for_each(|s| {
bytes.extend(build_name_seg(s));
})
}
}
bytes
}
/// This struct represents declaration of a named object
pub struct AmlNameDecl {
/// Name of the object.
name: String,
/// The corresponding object that be named.
obj: Vec<u8>,
}
impl AmlNameDecl {
pub fn new<T: AmlBuilder>(name: &str, obj: T) -> AmlNameDecl {
AmlNameDecl {
name: name.to_string(),
obj: obj.aml_bytes(),
}
}
}
impl AmlBuilder for AmlNameDecl {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x08];
bytes.extend(build_name_string(self.name.as_ref()));
bytes.extend(self.obj.clone());
bytes
}
}
/// AmlName represents a Named object that has been declared before.
#[derive(Clone)]
pub struct AmlName(pub String);
impl AmlBuilder for AmlName {
fn aml_bytes(&self) -> Vec<u8> {
build_name_string(self.0.as_ref())
}
}
/// EISA ID String
pub struct AmlEisaId {
name: String,
}
impl AmlEisaId {
pub fn new(name: &str) -> AmlEisaId {
if name.len() != 7 {
panic!("Eisa: String length is not 7.");
}
AmlEisaId {
name: name.to_string(),
}
}
}
impl AmlBuilder for AmlEisaId {
fn aml_bytes(&self) -> Vec<u8> {
let chars = self.name.chars().collect::<Vec<_>>();
let dword: u32 = (chars[0] as u32 - 0x40) << 26
| (chars[1] as u32 - 0x40) << 21
| (chars[2] as u32 - 0x40) << 16
| chars[3].to_digit(16).unwrap() << 12
| chars[4].to_digit(16).unwrap() << 8
| chars[5].to_digit(16).unwrap() << 4
| chars[6].to_digit(16).unwrap();
let mut bytes = dword.as_bytes().to_vec();
bytes.reverse();
bytes.insert(0, 0x0C);
bytes
}
}
/// Convert an ASCII string to a 128-bit buffer.
/// format: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
pub struct AmlToUuid {
name: String,
}
impl AmlToUuid {
pub fn new(str: &str) -> AmlToUuid {
let name = str.to_string();
if !Self::check_valid_uuid(&name) {
panic!("Invalid UUID");
}
AmlToUuid { name }
}
/// Check if the uuid is valid.
fn check_valid_uuid(uuid: &str) -> bool {
if uuid.len() != 36 {
return false;
}
// Char located at 8, 13, 18, 23 should be `-`
let indexs = &[8, 13, 18, 23];
for i in indexs {
if uuid.chars().nth(*i).unwrap() != '-' {
return false;
}
}
for ch in uuid.chars() {
if ch != '-' && (!ch.is_ascii_hexdigit()) {
return false;
}
}
true
}
}
impl AmlBuilder for AmlToUuid {
fn aml_bytes(&self) -> Vec<u8> {
let mut uuid_bytes = Vec::new();
// If the UUID is "aabbccdd-eeff-gghh-iijj-kkllmmnnoopp", then the encoded order is:
// dd cc bb aa ff ee hh gg ii jj kk ll mm nn oo pp
let index = &[6, 4, 2, 0, 11, 9, 16, 14, 19, 21, 24, 26, 28, 30, 32, 34];
for i in index {
let mut chars = self.name.chars();
uuid_bytes.push(
(chars.nth(*i).unwrap().to_digit(16).unwrap() as u8) << 4
| chars.next().unwrap().to_digit(16).unwrap() as u8,
);
}
let mut bytes = vec![0x11];
// ToUUID is a Buffer, so the `opcode` and `pkg_length` have to be added in the front.
let len_bytes = AmlInteger(uuid_bytes.len() as u64).aml_bytes();
bytes.extend(build_pkg_length(len_bytes.len() + uuid_bytes.len(), true));
bytes.extend(len_bytes);
bytes.extend(uuid_bytes);
bytes
}
}
// Follow ACPI spec: 5.4 Definition Block Encoding
// The lower two bits indicates how many bytes are used for PkgLength
// The 3,4 bits are only used if PkgLength consists of one bytes.
// Therefore, the max value of PkgLength is 0x3F(one-byte encoding),
// 0xF_FF(two-byte encoding), 0xF_FF_FF(three-byte encoding), 0xF_FF_FF_FF(four-byte encoding).
/// Calculate PkgLength according to the length, and convert it to bytes.
fn build_pkg_length(length: usize, include_self: bool) -> Vec<u8> {
let pkg_1byte_shift = 6;
let pkg_2byte_shift = 4;
let pkg_3byte_shift = 12;
let pkg_4byte_shift = 20;
let mut pkg_length = length;
let mut bytes = Vec::new();
let bytes_count = if length + 1 < (1 << pkg_1byte_shift) {
1
} else if length + 2 < (1 << pkg_3byte_shift) {
2
} else if length + 3 < (1 << pkg_4byte_shift) {
3
} else {
4
};
if include_self {
pkg_length += bytes_count;
}
match bytes_count {
1 => {
bytes.push(pkg_length as u8);
}
2 => {
bytes.push((1 << pkg_1byte_shift | (pkg_length & 0xF)) as u8);
bytes.push((pkg_length >> pkg_2byte_shift) as u8);
}
3 => {
bytes.push((2 << pkg_1byte_shift | (pkg_length & 0xF)) as u8);
bytes.push((pkg_length >> pkg_2byte_shift) as u8);
bytes.push((pkg_length >> pkg_3byte_shift) as u8);
}
4 => {
bytes.push((3 << pkg_1byte_shift | (pkg_length & 0xF)) as u8);
bytes.push((pkg_length >> pkg_2byte_shift) as u8);
bytes.push((pkg_length >> pkg_3byte_shift) as u8);
bytes.push((pkg_length >> pkg_4byte_shift) as u8);
}
_ => panic!("Undefined PkgLength"),
}
bytes
}
/// Buffer declaration, represents an array of bytes.
/// When a byte stream cannot by `AmlByte`, `AmlQWord`, etc, Buffer can be used.
pub struct AmlBuffer(pub Vec<u8>);
impl AmlBuilder for AmlBuffer {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x11];
let len_bytes = AmlInteger(self.0.len() as u64).aml_bytes();
bytes.extend(build_pkg_length(len_bytes.len() + self.0.len(), true));
bytes.extend(len_bytes);
bytes.extend(self.0.clone());
bytes
}
}
/// Package contains an array of other objects.
pub struct AmlPackage {
elem_count: u8,
buf: Vec<u8>,
}
impl AmlPackage {
pub fn new(elem_count: u8) -> AmlPackage {
AmlPackage {
elem_count,
buf: vec![elem_count],
}
}
}
impl AmlBuilder for AmlPackage {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x12];
bytes.extend(build_pkg_length(self.buf.len(), true));
bytes.extend(self.buf.clone());
bytes
}
}
impl AmlScopeBuilder for AmlPackage {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// Variable-sized Package.
pub struct AmlVarPackage {
elem_count: u8,
buf: Vec<u8>,
}
impl AmlVarPackage {
pub fn new(elem_count: u8) -> AmlVarPackage {
AmlVarPackage {
elem_count,
buf: vec![elem_count],
}
}
}
impl AmlBuilder for AmlVarPackage {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x13];
bytes.extend(build_pkg_length(self.buf.len(), true));
bytes.extend(self.buf.clone());
bytes
}
}
impl AmlScopeBuilder for AmlVarPackage {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// Operation region address space type.
#[allow(clippy::upper_case_acronyms)]
#[derive(Copy, Clone)]
pub enum AmlAddressSpaceType {
/// System memory
SystemMemory = 0,
/// System IO
SystemIO = 1,
/// PCI config space
PCIConfig = 2,
/// Embedded controller space
EmbeddedControl = 3,
/// SMBus
SMBus = 4,
/// CMOS
SystemCMOS = 5,
/// PCI Bar target
PciBarTarget = 6,
/// IPMI
IPMI = 7,
/// General Purpose IO
GeneralPurposeIO = 8,
/// Generic serial bus
GenericSerialBus = 9,
/// Platform Communications Channel
PCC = 10,
}
/// Operation Region: defines a named objects of certain type: SystemMemory, SystemIo, etc.
/// OperationRegion also contains the start address and size.
pub struct AmlOpRegion {
/// Name of Operation region.
name: String,
/// System space type.
space_type: AmlAddressSpaceType,
/// Start address.
offset: u64,
/// Range length.
length: u64,
}
impl AmlOpRegion {
pub fn new(
name: &str,
space_type: AmlAddressSpaceType,
offset: u64,
length: u64,
) -> AmlOpRegion {
AmlOpRegion {
name: name.to_string(),
space_type,
offset,
length,
}
}
}
impl AmlBuilder for AmlOpRegion {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x5B, 0x80];
bytes.extend(build_name_string(self.name.as_ref()));
bytes.push(self.space_type as u8);
bytes.extend(AmlInteger(self.offset).aml_bytes());
bytes.extend(AmlInteger(self.length).aml_bytes());
bytes
}
}
/// Access width of this field.
#[derive(Copy, Clone)]
pub enum AmlFieldAccessType {
Any = 0,
Byte = 1,
Word = 2,
DWord = 3,
QWord = 4,
Buffer = 5,
}
/// Flag that indicates whether the Global Lock is to be used
/// when accessing this field
#[derive(Copy, Clone)]
pub enum AmlFieldLockRule {
NoLock = 0,
Lock = 1,
}
/// Flag that indicates how the unmodified bits of a field are treated
#[derive(Copy, Clone)]
pub enum AmlFieldUpdateRule {
Preserve = 0,
WriteAsOnes = 1,
WriteAsZeros = 2,
}
/// Field represents several bits in Operation Field.
pub struct AmlField {
/// The name of corresponding OperationRegion.
name: String,
/// The access type of this Field.
access_type: AmlFieldAccessType,
/// Global lock is to be used or not when accessing this field.
lock_rule: AmlFieldLockRule,
/// Unmodified bits of a field are treated as Ones/Zeros/Preserve.
update_rule: AmlFieldUpdateRule,
/// Field Unit list.
buf: Vec<u8>,
}
impl AmlField {
pub fn new(
name: &str,
acc_ty: AmlFieldAccessType,
lock_r: AmlFieldLockRule,
update_r: AmlFieldUpdateRule,
) -> AmlField {
let mut bytes = Vec::new();
let flag = ((update_r as u8) << 5) | ((lock_r as u8) << 1) | (acc_ty as u8 & 0x0F);
bytes.extend(build_name_string(name));
bytes.push(flag);
AmlField {
name: name.to_string(),
access_type: acc_ty,
lock_rule: lock_r,
update_rule: update_r,
buf: bytes,
}
}
}
impl AmlBuilder for AmlField {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x5B, 0x81];
bytes.extend(build_pkg_length(self.buf.len(), true));
bytes.extend(self.buf.clone());
bytes
}
}
impl AmlScopeBuilder for AmlField {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// Field unit that defines inside Field-scope.
pub struct AmlFieldUnit {
/// The name of this Field unit. `None` value indicate that this field is reserved.
name: Option<String>,
/// The Byte length of this Field unit.
length: u32,
}
impl AmlFieldUnit {
pub fn new(name: Option<&str>, length: u32) -> AmlFieldUnit {
AmlFieldUnit {
name: name.map(|s| s.to_string()),
length,
}
}
}
impl AmlBuilder for AmlFieldUnit {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = self
.name
.as_ref()
.map(|str| build_name_seg(str))
.unwrap_or_else(|| vec![0x0_u8]);
bytes.extend(build_pkg_length(self.length as usize, false));
bytes
}
}
/// Open a named Scope, can refer any scope within the namespace.
pub struct AmlScope {
/// The name of scope.
name: String,
/// Contains objects created inside the scope, which are encodes to bytes.
buf: Vec<u8>,
}
impl AmlScope {
pub fn new(name: &str) -> AmlScope {
AmlScope {
name: name.to_string(),
buf: build_name_string(name),
}
}
pub fn append(&mut self, data: &[u8]) {
self.buf.extend(data);
}
}
impl AmlBuilder for AmlScope {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x10];
bytes.extend(build_pkg_length(self.buf.len(), true));
bytes.extend(self.buf.clone());
bytes
}
}
impl AmlScopeBuilder for AmlScope {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// Device object that represents a processor, a device, etc.
pub struct AmlDevice {
name: String,
buf: Vec<u8>,
}
impl AmlDevice {
pub fn new(name: &str) -> AmlDevice {
AmlDevice {
name: name.to_string(),
buf: build_name_string(name),
}
}
}
impl AmlBuilder for AmlDevice {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x5B, 0x82];
bytes.extend(build_pkg_length(self.buf.len(), true));
bytes.extend(self.buf.clone());
bytes
}
}
impl AmlScopeBuilder for AmlDevice {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// Method definition.
pub struct AmlMethod {
/// The name of this method.
name: String,
/// Count of Arguments. default value is zero.
args_count: u8,
/// Whether this method is Serialized or not.
serialized: bool,
/// The body of this method, which has been converted to byte stream.
buf: Vec<u8>,
}
impl AmlMethod {
pub fn new(name: &str, args_count: u8, serialized: bool) -> AmlMethod {
if args_count > 7 {
panic!("Up to 7 arguments are supported, given {}", args_count);
}
// Method Flags:
// bit 0-2: ArgCount (0-7)
// bit 3: SerializeFlag
// 0 NotSerialized
// 1 Serialized
let mut flag = args_count;
if serialized {
flag |= 1 << 3;
}
let mut bytes = build_name_string(name);
bytes.push(flag);
AmlMethod {
name: name.to_string(),
args_count,
serialized,
buf: bytes,
}
}
}
impl AmlBuilder for AmlMethod {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x14];
bytes.extend(build_pkg_length(self.buf.len(), true));
bytes.extend(self.buf.clone());
bytes
}
}
impl AmlScopeBuilder for AmlMethod {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// Local variables that can be used in method, Local(0)~Local(7)
#[derive(Copy, Clone)]
pub struct AmlLocal(pub u8);
impl AmlBuilder for AmlLocal {
fn aml_bytes(&self) -> Vec<u8> {
if self.0 > 7 {
panic!("Up to 8 Local are supported, given {}", self.0);
}
vec![0x60 + self.0]
}
}
/// Arguments passed to method, Arg(0)~Arg(6)
#[derive(Copy, Clone)]
pub struct AmlArg(pub u8);
impl AmlBuilder for AmlArg {
fn aml_bytes(&self) -> Vec<u8> {
if self.0 > 6 {
panic!("Up to 7 Arguments are supported, given {}", self.0);
}
vec![0x68 + self.0]
}
}
/// Return from method
pub struct AmlReturn {
value: Vec<u8>,
}
impl AmlReturn {
/// Return with nothing.
#[allow(clippy::new_without_default)]
pub fn new() -> AmlReturn {
AmlReturn { value: vec![0x00] }
}
/// Return an object or reference.
pub fn with_value<T: AmlBuilder>(val: T) -> AmlReturn {
AmlReturn {
value: val.aml_bytes(),
}
}
}
impl AmlBuilder for AmlReturn {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0xA4];
bytes.extend(self.value.clone());
bytes
}
}
// Macro that helps to define `MethodCallWithArgsx`.
macro_rules! method_call_define {
($name: ident) => {
#[derive(Clone)]
/// Call a method.
pub struct $name {
/// Name of the method that will be called.
name: String,
/// The arguments that will be passed to the method. Note that
/// the arguments provided must match to the arguments' count of the method.
buf: Vec<u8>,
}
impl AmlBuilder for $name {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend(build_name_string(&self.name));
bytes.extend(self.buf.clone());
bytes
}
}
};
}
// AmlCallWithArgs1 represents calling method with 1 argument.
method_call_define!(AmlCallWithArgs1);
// AmlCallWithArgs2 represents calling method with 2 arguments.
method_call_define!(AmlCallWithArgs2);
// AmlCallWithArgs3 represents calling method with 3 arguments.
method_call_define!(AmlCallWithArgs3);
// AmlCallWithArgs4 represents calling method with 4 arguments.
method_call_define!(AmlCallWithArgs4);
// AmlCallWithArgs5 represents calling method with 5 arguments.
method_call_define!(AmlCallWithArgs5);
impl AmlCallWithArgs1 {
pub fn new<A: AmlBuilder>(name: &str, arg0: A) -> AmlCallWithArgs1 {
let mut bytes = Vec::new();
bytes.extend(arg0.aml_bytes());
AmlCallWithArgs1 {
name: name.to_string(),
buf: bytes,
}
}
}
impl AmlCallWithArgs2 {
pub fn new<A: AmlBuilder, B: AmlBuilder>(name: &str, arg0: A, arg1: B) -> AmlCallWithArgs2 {
let mut bytes = Vec::new();
bytes.extend(arg0.aml_bytes());
bytes.extend(arg1.aml_bytes());
AmlCallWithArgs2 {
name: name.to_string(),
buf: bytes,
}
}
}
impl AmlCallWithArgs3 {
pub fn new<A: AmlBuilder, B: AmlBuilder, C: AmlBuilder>(
name: &str,
arg0: A,
arg1: B,
arg2: C,
) -> AmlCallWithArgs3 {
let mut bytes = Vec::new();
bytes.extend(arg0.aml_bytes());
bytes.extend(arg1.aml_bytes());
bytes.extend(arg2.aml_bytes());
AmlCallWithArgs3 {
name: name.to_string(),
buf: bytes,
}
}
}
impl AmlCallWithArgs4 {
pub fn new<A: AmlBuilder, B: AmlBuilder, C: AmlBuilder, D: AmlBuilder>(
name: &str,
arg0: A,
arg1: B,
arg2: C,
arg3: D,
) -> AmlCallWithArgs4 {
let mut bytes = Vec::new();
bytes.extend(arg0.aml_bytes());
bytes.extend(arg1.aml_bytes());
bytes.extend(arg2.aml_bytes());
bytes.extend(arg3.aml_bytes());
AmlCallWithArgs4 {
name: name.to_string(),
buf: bytes,
}
}
}
impl AmlCallWithArgs5 {
pub fn new<A: AmlBuilder, B: AmlBuilder, C: AmlBuilder, D: AmlBuilder, E: AmlBuilder>(
name: &str,
arg0: A,
arg1: B,
arg2: C,
arg3: D,
arg4: E,
) -> AmlCallWithArgs5 {
let mut bytes = Vec::new();
bytes.extend(arg0.aml_bytes());
bytes.extend(arg1.aml_bytes());
bytes.extend(arg2.aml_bytes());
bytes.extend(arg3.aml_bytes());
bytes.extend(arg4.aml_bytes());
AmlCallWithArgs5 {
name: name.to_string(),
buf: bytes,
}
}
}
/// Macro that helps to define Aml Data structures that
/// contains two arguments and one destination.
macro_rules! ops_2args_dst_define {
($name:ident, $op:expr) => {
pub struct $name {
arg1: Vec<u8>,
arg2: Vec<u8>,
dst: Vec<u8>,
}
impl $name {
pub fn new<A: AmlBuilder, B: AmlBuilder, D: AmlBuilder>(a1: A, a2: B, d: D) -> $name {
$name {
arg1: a1.aml_bytes(),
arg2: a2.aml_bytes(),
dst: d.aml_bytes(),
}
}
}
impl AmlBuilder for $name {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![$op];
bytes.extend(self.arg1.clone());
bytes.extend(self.arg2.clone());
bytes.extend(self.dst.clone());
bytes
}
}
};
}
ops_2args_dst_define!(AmlAdd, 0x72);
ops_2args_dst_define!(AmlSubtract, 0x74);
// Concatenate two strings, integers or buffers and store the result in Destination.
ops_2args_dst_define!(AmlConcat, 0x73);
ops_2args_dst_define!(AmlAnd, 0x7B);
ops_2args_dst_define!(AmlOr, 0x7D);
ops_2args_dst_define!(AmlShiftLeft, 0x79);
ops_2args_dst_define!(AmlShiftRight, 0x7A);
// Indexed Reference to member object.
// The first argument refers to the source that can be Buffer, Package or String.
// The second argument refers to the index.
// The corresponding reference to the field is stored in Destination.
ops_2args_dst_define!(AmlIndex, 0x88);
/// Macro that helps to define Aml Data structures that contains one argument.
macro_rules! ops_1arg_define {
($name:ident, $op:expr) => {
pub struct $name {
arg: Vec<u8>,
}
impl $name {
pub fn new<T: AmlBuilder>(a1: T) -> $name {
$name {
arg: a1.aml_bytes(),
}
}
}
impl AmlBuilder for $name {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![$op];
bytes.extend(self.arg.clone());
bytes
}
}
};
}
// Increment/Decrement: Arg1 is an Integer.
ops_1arg_define!(AmlIncrement, 0x75);
ops_1arg_define!(AmlDecrement, 0x76);
// Logical Not: Arg1 is an Integer.
ops_1arg_define!(AmlLNot, 0x92);
// SizeOf: Arg1 must be an Buffer, String or Package.
ops_1arg_define!(AmlSizeOf, 0x87);
// DeRefOf is necessary in the first operand of the Store operator
// in order to get the actual object, rather than just a reference to the object.
// If DeRefOf were not used, then `Index` would contain an object reference to the element.
// Below is an example:
//
// ```
// let buffer = AmlBuffer::new(vec![0x1, 0x2, 0x3]);
// let arg1 = AmlDeRefOf::new(AmlIndex::new(buffer, 1));
// let store = AmlStore::new(arg1, Local(0));
// ```
ops_1arg_define!(AmlDeRefOf, 0x83);
/// Macro that helps to define Aml Data structures that contains two arguments.
macro_rules! ops_2arg_define {
($name:ident, $op:expr) => {
pub struct $name {
arg1: Vec<u8>,
arg2: Vec<u8>,
}
impl $name {
pub fn new<A: AmlBuilder, B: AmlBuilder>(a1: A, a2: B) -> $name {
$name {
arg1: a1.aml_bytes(),
arg2: a2.aml_bytes(),
}
}
}
impl AmlBuilder for $name {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![$op];
bytes.extend(self.arg1.clone());
bytes.extend(self.arg2.clone());
bytes
}
}
};
}
// Store the source value(Arg1) to the destination(Arg2).
ops_2arg_define!(AmlStore, 0x70);
// Notify the Object(Arg1) that the NotificationValue(Arg2) has occurred.
ops_2arg_define!(AmlNotify, 0x86);
// Logical Equal/Greater/Less/And/Or:
// Arg1 and Arg2 must be the same type. Integer, String and Buffer are supported.
// Return True or False;
ops_2arg_define!(AmlEqual, 0x93);
ops_2arg_define!(AmlLGreater, 0x94);
ops_2arg_define!(AmlLLess, 0x95);
ops_2arg_define!(AmlLAnd, 0x90);
ops_2arg_define!(AmlLOr, 0x91);
/// If scope
pub struct AmlIf {
/// Predicate and the operations in the if-scope is converted to byte stream.
buf: Vec<u8>,
}
impl AmlIf {
pub fn new<T: AmlBuilder>(predicate: T) -> AmlIf {
AmlIf {
buf: predicate.aml_bytes(),
}
}
}
impl AmlBuilder for AmlIf {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0xA0];
bytes.extend(build_pkg_length(self.buf.len(), true));
bytes.extend(self.buf.clone());
bytes
}
}
impl AmlScopeBuilder for AmlIf {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// Else scope
pub struct AmlElse {
/// Predicate and the operations in the else-scope is converted to byte stream.
buf: Vec<u8>,
}
impl AmlElse {
#[allow(clippy::new_without_default)]
pub fn new() -> AmlElse {
AmlElse { buf: Vec::new() }
}
}
impl AmlBuilder for AmlElse {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0xA1];
bytes.extend(build_pkg_length(self.buf.len(), true));
bytes.extend(self.buf.clone());
bytes
}
}
impl AmlScopeBuilder for AmlElse {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// While scope
pub struct AmlWhile {
/// Predicate and the operations in the while-scope is converted to byte stream.
buf: Vec<u8>,
}
impl AmlWhile {
pub fn new<T: AmlBuilder>(predicate: T) -> AmlWhile {
AmlWhile {
buf: predicate.aml_bytes(),
}
}
}
impl AmlBuilder for AmlWhile {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0xA2];
bytes.extend(build_pkg_length(self.buf.len(), true));
bytes.extend(self.buf.clone());
bytes
}
}
impl AmlScopeBuilder for AmlWhile {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// This struct represents a Mutex.
pub struct AmlMutex {
/// Name of the mutex.
name: String,
/// The synchronization level of the mutex. Default value is zero.
sync_level: u8,
}
impl AmlMutex {
pub fn new(name: &str, sync_level: u8) -> AmlMutex {
if sync_level > 15 {
panic!(
"Supported sync level of mutex is 0~15, given {}",
sync_level
);
}
AmlMutex {
name: name.to_string(),
sync_level,
}
}
}
impl AmlBuilder for AmlMutex {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x5B, 0x01];
bytes.extend(build_name_string(self.name.as_ref()));
bytes.push(self.sync_level);
bytes
}
}
/// Acquire a mutex. Returns True if timeout occurs or can not acquire the mutex.
pub struct AmlAcquire {
/// The mutex object is converted to byte stream.
mutex: Vec<u8>,
/// If the mutex is owned by others, current thread suspends and waits for `timeout` **milliseconds**
/// `timeout` being set as 0xFFFF indicates that there is no timeout and
/// the acquire mutex operation will keeping waiting.
time_out: u16,
}
impl AmlAcquire {
pub fn new<T: AmlBuilder>(mtx: T, time_out: u16) -> AmlAcquire {
AmlAcquire {
mutex: mtx.aml_bytes(),
time_out,
}
}
}
impl AmlBuilder for AmlAcquire {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x5B, 0x23];
bytes.extend(self.mutex.clone());
bytes.extend(self.time_out.as_bytes());
bytes
}
}
/// Release the ownership of the mutex.
pub struct AmlRelease {
/// the mutex that has been acquired before.
mutex: Vec<u8>,
}
impl AmlRelease {
fn new<T: AmlBuilder>(mtx: T) -> AmlRelease {
AmlRelease {
mutex: mtx.aml_bytes(),
}
}
}
impl AmlBuilder for AmlRelease {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x5B, 0x27];
bytes.extend(self.mutex.clone());
bytes
}
}
/// Create arbitrary-length field of Buffer.
pub struct AmlCreateField {
/// The name of this field.
name: String,
/// The source Buffer, which has been converted to bytes.
src: Vec<u8>,
/// the start index in the Buffer, which has been converted to bytes.
/// `bit_index` has to be an Integer.
bit_index: Vec<u8>,
/// the length of this bit range, which has been converted to bytes.
/// `bit_count` has to be an Integer and must not be zero.
/// Note that the bit range (bit_index, bit_index + bit_count) must not exceed the bound of Buffer.
bit_count: Vec<u8>,
}
impl AmlCreateField {
pub fn new<S: AmlBuilder, T: AmlBuilder, C: AmlBuilder>(
src: S,
bit_index: T,
bit_count: C,
name: &str,
) -> AmlCreateField {
AmlCreateField {
name: name.to_string(),
src: src.aml_bytes(),
bit_index: bit_index.aml_bytes(),
bit_count: bit_count.aml_bytes(),
}
}
}
impl AmlBuilder for AmlCreateField {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x5B, 0x13];
bytes.extend(self.src.clone());
bytes.extend(self.bit_index.clone());
bytes.extend(self.bit_count.clone());
bytes.extend(build_name_string(self.name.as_ref()));
bytes
}
}
/// Macro helps to define CreateWordField/CreateDWordField/CreateQWordField.
macro_rules! create_word_field_define {
($name: ident, $op: expr) => {
pub struct $name {
name: String,
src: Vec<u8>,
bit_index: Vec<u8>,
}
impl $name {
pub fn new<S: AmlBuilder, T: AmlBuilder>(src: S, bit_index: T, name: &str) -> $name {
$name {
name: name.to_string(),
src: src.aml_bytes(),
bit_index: bit_index.aml_bytes(),
}
}
}
impl AmlBuilder for $name {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![$op];
bytes.extend(self.src.clone());
bytes.extend(self.bit_index.clone());
bytes.extend(build_name_string(self.name.as_ref()));
bytes
}
}
};
}
// As for the below operations, The length of field are fixed.
create_word_field_define!(AmlCreateWordField, 0x8B);
create_word_field_define!(AmlCreateDWordField, 0x8A);
create_word_field_define!(AmlCreateQWordField, 0x8F);
/// Resource Template are used to create resource descriptors.
/// In its scope, multiple resource descriptors are listed to
/// specify the resource owned by a device.
pub struct AmlResTemplate {
buf: Vec<u8>,
}
impl AmlResTemplate {
#[allow(clippy::new_without_default)]
pub fn new() -> AmlResTemplate {
AmlResTemplate { buf: Vec::new() }
}
}
impl AmlBuilder for AmlResTemplate {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
// fill buffer and end tag
let end_tag_len = 2_u64;
bytes.extend(AmlInteger(self.buf.len() as u64 + end_tag_len).aml_bytes());
bytes.extend(self.buf.clone());
bytes.push(0x79); // end tag
bytes.push(0x00);
// fill prepend PkgLength
let pkg_length = build_pkg_length(bytes.len(), true);
pkg_length.iter().rev().for_each(|b| {
bytes.insert(0, *b);
});
// fill resource template opcode.
bytes.insert(0, 0x11);
bytes
}
}
impl AmlScopeBuilder for AmlResTemplate {
fn append_child<T: AmlBuilder>(&mut self, child: T) {
self.buf.extend(child.aml_bytes());
}
}
/// The type of DMA cycle.
#[derive(Copy, Clone)]
pub enum AmlDmaType {
/// ISA compatible.
Compatibility = 0,
/// EISA TypeA.
TypeA = 1,
/// EISA TypeB.
TypeB = 2,
/// EISA TypeF.
TypeF = 3,
}
/// The size of DMA cycles that the device is capable of generating.
#[derive(Copy, Clone)]
pub enum AmlDmaTransSize {
Size8 = 0,
Size8_16 = 1,
Size16 = 2,
}
#[derive(Copy, Clone)]
pub struct AmlDmaResource {
/// The type of DMA cycle
dma_type: AmlDmaType,
/// Whether the device can generate DMA bus master cycles.
is_master: bool,
/// The size of DMA cycle.
trans_sz: AmlDmaTransSize,
/// DMA channel used by the device, range 0~7.
channel: u8,
}
impl AmlDmaResource {
pub fn new(
dma_type: AmlDmaType,
is_master: bool,
trans_sz: AmlDmaTransSize,
channel: u8,
) -> AmlDmaResource {
if channel > 7 {
panic!("acpi: DMA channel exceeds range 0~7.");
}
AmlDmaResource {
dma_type,
is_master,
trans_sz,
channel,
}
}
}
impl AmlBuilder for AmlDmaResource {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x2A, 1 << self.channel];
let mut flags = (self.trans_sz as u8) | (self.dma_type as u8) << 5;
if self.is_master {
flags |= 1 << 2; // Bit-2 represents bus master
}
bytes.push(flags);
bytes
}
}
/// Decode type of IO resource.
#[derive(Copy, Clone)]
pub enum AmlIoDecode {
/// 10-bit decode is used.
Decode10 = 0,
/// 16-bit decode is used.
Decode16 = 1,
}
/// IO Resource descriptor.
#[derive(Copy, Clone)]
pub struct AmlIoResource {
/// Decode type.
decode: AmlIoDecode,
/// The minimum acceptable start address.
min_addr: u16,
/// The maximum acceptable start address.
max_addr: u16,
/// The alignment granularity for the I/O address assigned.
align: u8,
/// The number of bytes in the I/O range.
length: u8,
}
impl AmlIoResource {
pub fn new(
decode: AmlIoDecode,
min_addr: u16,
max_addr: u16,
align: u8,
length: u8,
) -> AmlIoResource {
AmlIoResource {
decode,
min_addr,
max_addr,
align,
length,
}
}
}
impl AmlBuilder for AmlIoResource {
fn aml_bytes(&self) -> Vec<u8> {
vec![
0x47,
self.decode as u8,
(self.min_addr & 0xFF) as u8,
(self.min_addr >> 8) as u8,
(self.max_addr & 0xFF) as u8,
(self.max_addr >> 8) as u8,
self.align,
self.length,
]
}
}
/// Access status of memory resource.
#[derive(Copy, Clone)]
pub enum AmlReadAndWrite {
/// Non-writeable (read-only)
ReadOnly = 0,
/// Writeable (read/write)
ReadWrite = 1,
}
/// Memory resource within 32-bit address space.
pub struct AmlMemory32Fixed {
/// Access right.
rw_access: AmlReadAndWrite,
/// Start address.
addr: u32,
/// Range length.
length: u32,
}
impl AmlMemory32Fixed {
pub fn new(rw_access: AmlReadAndWrite, addr: u32, length: u32) -> AmlMemory32Fixed {
AmlMemory32Fixed {
rw_access,
addr,
length,
}
}
}
impl AmlBuilder for AmlMemory32Fixed {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x86, 0x09, 0x00, self.rw_access as u8];
bytes.extend(self.addr.as_bytes());
bytes.extend(self.length.as_bytes());
bytes
}
}
/// Cacheable features.
#[derive(Copy, Clone)]
pub enum AmlCacheable {
NonCacheable = 0,
Cacheable = 1,
WriteCombining = 2,
Prefetchable = 3,
}
/// This enum determines how the IO resource are limited.
#[allow(clippy::upper_case_acronyms)]
#[derive(Copy, Clone)]
pub enum AmlISARanges {
/// Limited to valid ISA I/O ranges.
ISAOnly = 1,
/// Limited to valid non-ISA I/O ranges.
NonISAOnly = 2,
/// No limitation
EntireRange = 3,
}
/// The type of resource.
#[allow(clippy::upper_case_acronyms)]
#[derive(Copy, Clone)]
pub enum AmlResourceType {
Memory = 0,
IO = 1,
BusNumber = 2,
}
/// Decode type of bus number range.
#[derive(Copy, Clone)]
pub enum AmlAddressSpaceDecode {
/// Positive decode.
Positive = 0,
/// Subtract decode.
Subtract = 1,
}
/// Macro that helps to define Word/DWord/QWord address space descriptors.
macro_rules! space_desc_define {
($name: ident, $op:expr, $ml: expr, $ty: tt) => {
pub struct $name {
res_type: AmlResourceType,
decode: AmlAddressSpaceDecode,
type_flags: u8,
granularity: $ty,
addr_min: $ty,
addr_max: $ty,
addr_trans: $ty,
length: $ty,
}
impl AmlBuilder for $name {
fn aml_bytes(&self) -> Vec<u8> {
// min_addr and max_addr are fixed
let flags = (self.decode as u8) << 1 | 1 << 2 | 1 << 3;
let mut bytes = vec![$op, $ml, 0x00, self.res_type as u8, flags, self.type_flags];
bytes.extend(self.granularity.as_bytes());
bytes.extend(self.addr_min.as_bytes());
bytes.extend(self.addr_max.as_bytes());
bytes.extend(self.addr_trans.as_bytes());
bytes.extend(self.length.as_bytes());
bytes
}
}
};
}
/// Macro that helps to define DWordDesc/QWordDesc's construct function.
macro_rules! struct_new_memory_define {
($name: ident, $ty: tt) => {
impl $name {
#[allow(clippy::too_many_arguments)]
pub fn new_memory(
decode: AmlAddressSpaceDecode,
cache: AmlCacheable,
rw: AmlReadAndWrite,
gran: $ty,
min: $ty,
max: $ty,
trans: $ty,
len: $ty,
) -> $name {
let type_flags = rw as u8 | (cache as u8) << 1;
$name {
res_type: AmlResourceType::Memory,
decode,
type_flags,
granularity: gran,
addr_min: min,
addr_max: max,
addr_trans: trans,
length: len,
}
}
}
};
}
/// Macro that helps to define WordDesc/DWordDesc/QWordDesc's construct function.
macro_rules! struct_new_io_define {
($name: ident, $ty: tt) => {
impl $name {
#[allow(clippy::too_many_arguments)]
pub fn new_io(
decode: AmlAddressSpaceDecode,
isa_ranges: AmlISARanges,
gran: $ty,
min: $ty,
max: $ty,
trans: $ty,
len: $ty,
) -> $name {
$name {
res_type: AmlResourceType::IO,
decode,
type_flags: isa_ranges as u8,
granularity: gran,
addr_min: min,
addr_max: max,
addr_trans: trans,
length: len,
}
}
}
};
}
// Word address space descriptor, which can be used to describe IO and BusNumber.
space_desc_define!(AmlWordDesc, 0x88, 0x0D, u16);
// Define `AmlWordDesc::new_io()` function to construct WordIO-type resource.
struct_new_io_define!(AmlWordDesc, u16);
// Define `AmlWordDesc::new_bus_number()` function to construct WordBusNumber-type resource.
impl AmlWordDesc {
pub fn new_bus_number(
decode: AmlAddressSpaceDecode,
gran: u16,
min: u16,
max: u16,
trans: u16,
len: u16,
) -> AmlWordDesc {
AmlWordDesc {
res_type: AmlResourceType::BusNumber,
decode,
type_flags: 0,
granularity: gran,
addr_min: min,
addr_max: max,
addr_trans: trans,
length: len,
}
}
}
// DWord address space descriptor, which can be used to describe IO and Memory.
space_desc_define!(AmlDWordDesc, 0x87, 23, u32);
// Define `AmlDWordDesc::new_io()` function to construct DWordIO-type resource.
struct_new_io_define!(AmlDWordDesc, u32);
// Define `AmlDWordDesc::new_memory()` function to construct DWordMemory-type resource.
struct_new_memory_define!(AmlDWordDesc, u32);
// QWord address space descriptor, which can be used to describe Memory.
space_desc_define!(AmlQWordDesc, 0x8A, 0x2B, u64);
// Define `AmlQWordDesc::new_memory()` function to construct QWordMemory-type resource.
struct_new_memory_define!(AmlQWordDesc, u64);
/// Active-high, edge-triggered IRQ resource descriptor.
pub struct AmlIrqNoFlags {
/// Irq number.
irq: u8,
}
impl AmlIrqNoFlags {
pub fn new(irq: u8) -> AmlIrqNoFlags {
if irq > 15 {
panic!("acpi: Irq exceeds range 0~15.");
}
AmlIrqNoFlags { irq }
}
}
impl AmlBuilder for AmlIrqNoFlags {
fn aml_bytes(&self) -> Vec<u8> {
let irq_mask = 1 << (self.irq as u16);
vec![0x22, (irq_mask & 0xFF) as u8, (irq_mask >> 8) as u8]
}
}
/// Flags that indicates whether device consume or produce the interrupt resource.
#[derive(Copy, Clone)]
pub enum AmlResourceUsage {
/// Device will produce the interrupt for use by child device.
Producer = 0,
/// Device will consume the interrupt.
Consumer = 1,
}
/// Flags that indicates how the interrupt been triggered.
#[derive(Copy, Clone)]
pub enum AmlEdgeLevel {
/// Level triggered.
Level = 0,
/// Edge triggered.
Edge = 1,
}
/// Flags that indicates the interrupt is actively high or low.
#[derive(Copy, Clone)]
pub enum AmlActiveLevel {
/// Active-high.
High = 0,
/// Active-low.
Low = 1,
}
/// Flags that indicates whether the interrupt can be shared with other device.
#[derive(Copy, Clone)]
pub enum AmlIntShare {
/// Cannot be shared. Not Wake Capable.
Exclusive = 0,
/// Can share with other device. Not Wake Capable.
Share = 1,
/// Cannot be shared. Wake Capable.
ExclusiveWake = 2,
/// Can share with other device. Wake Capable.
ShareWake = 3,
}
/// Extended interrupt descriptor.
pub struct AmlExtendedInterrupt {
/// Produce or consume the interrupt.
usage: AmlResourceUsage,
/// Trigger mode.
int_mode: AmlEdgeLevel,
/// Active level.
int_polar: AmlActiveLevel,
/// Can be share or not.
share: AmlIntShare,
/// interrupt list.
irq_list: Vec<u32>,
}
impl AmlExtendedInterrupt {
pub fn new(
usage: AmlResourceUsage,
mode: AmlEdgeLevel,
polar: AmlActiveLevel,
share: AmlIntShare,
irq_list: Vec<u32>,
) -> AmlExtendedInterrupt {
if irq_list.is_empty() {
panic!("the list of irqs must not be empty.");
}
AmlExtendedInterrupt {
usage,
int_mode: mode,
int_polar: polar,
share,
irq_list,
}
}
}
impl AmlBuilder for AmlExtendedInterrupt {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0x89];
let header_len = 2_u16;
let total_len = header_len + (self.irq_list.len() * std::mem::size_of::<u32>()) as u16;
// the length is at least 6, for only one element in irq-list
bytes.extend(total_len.as_bytes());
let flags = self.usage as u8
| (self.int_mode as u8) << 1
| (self.int_polar as u8) << 2
| (self.share as u8) << 3;
bytes.push(flags);
bytes.push(self.irq_list.len() as u8);
self.irq_list
.iter()
.for_each(|irq| bytes.extend(irq.as_bytes()));
bytes
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_uuid() {
let uuid = AmlToUuid::new("33DB4D5B-1FF7-401C-9657-7441C03DD766");
assert_eq!(
uuid.aml_bytes(),
&[
0x11, 0x13, 0x0a, 0x10, 0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57,
0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66
]
);
}
#[test]
fn test_package() {
// Name (PKG1, Package(3){0x1234, "Hello world", INT1})
let mut pkg1 = AmlPackage::new(3);
pkg1.append_child(AmlInteger(0x1234));
pkg1.append_child(AmlString("Hello world".to_string()));
pkg1.append_child(AmlName("INT1".to_string()));
let named_pkg1 = AmlNameDecl::new("PKG1", pkg1);
let pkg1_bytes = vec![
0x08, 0x50, 0x4B, 0x47, 0x31, 0x12, 0x16, 0x03, 0x0B, 0x34, 0x12, 0x0D, 0x48, 0x65,
0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x00, 0x49, 0x4E, 0x54, 0x31,
];
assert_eq!(named_pkg1.aml_bytes(), pkg1_bytes);
// Name (PKG2, Package(){INT1, "Good bye"})
let mut pkg2 = AmlPackage::new(2);
pkg2.append_child(AmlName("INT1".to_string()));
pkg2.append_child(AmlString("Good bye".to_string()));
let named_pkg2 = AmlNameDecl::new("PKG2", pkg2);
let pkg2_bytes = vec![
0x08, 0x50, 0x4B, 0x47, 0x32, 0x12, 0x10, 0x02, 0x49, 0x4E, 0x54, 0x31, 0x0D, 0x47,
0x6F, 0x6F, 0x64, 0x20, 0x62, 0x79, 0x65, 0x00,
];
assert_eq!(named_pkg2.aml_bytes(), pkg2_bytes);
// Name (PKG3, Package(){
// "ASL is fun",
// Package() {0xff, 0xfe, 0xfd},
// Buffer() {0x01, 0x02}
// })
let mut pkg3 = AmlPackage::new(3);
pkg3.append_child(AmlString("ASL is fun".to_string()));
let mut pkg32 = AmlPackage::new(3);
pkg32.append_child(AmlInteger(0xff));
pkg32.append_child(AmlInteger(0xfe));
pkg32.append_child(AmlInteger(0xfd));
pkg3.append_child(pkg32);
let buffer = AmlBuffer(vec![0x01, 0x02]);
pkg3.append_child(buffer);
let named_pkg3 = AmlNameDecl::new("PKG3", pkg3);
let pkg3_bytes = vec![
0x08, 0x50, 0x4B, 0x47, 0x33, 0x12, 0x1D, 0x03, 0x0D, 0x41, 0x53, 0x4C, 0x20, 0x69,
0x73, 0x20, 0x66, 0x75, 0x6E, 0x00, 0x12, 0x08, 0x03, 0x0A, 0xFF, 0x0A, 0xFE, 0x0A,
0xFD, 0x11, 0x05, 0x0A, 0x02, 0x01, 0x02,
];
assert_eq!(named_pkg3.aml_bytes(), pkg3_bytes);
}
#[test]
fn test_op_region() {
// OperationRegion(OPR1, SystemMemory, 0x10000, 0x5)
// Field (OPR1, ByteAcc, NoLock, WriteAsZeros)
// {
// FLD1, 8,
// FLD2, 8,
// Offset (3), //Start the next field unit at byte offset 3
// FLD3, 4,
// FLD4, 12,
// }
let op_region = AmlOpRegion::new("OPR1", AmlAddressSpaceType::SystemMemory, 0x10000, 0x5);
let target = vec![
0x5B, 0x80, 0x4F, 0x50, 0x52, 0x31, 0x00, 0x0C, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x05,
];
assert_eq!(op_region.aml_bytes(), target);
let mut field = AmlField::new(
"OPR1",
AmlFieldAccessType::Byte,
AmlFieldLockRule::NoLock,
AmlFieldUpdateRule::WriteAsZeros,
);
let elem1 = AmlFieldUnit::new(Some("FLD1"), 8);
let elem2 = AmlFieldUnit::new(Some("FLD2"), 8);
let elem3 = AmlFieldUnit::new(None, 8);
let elem4 = AmlFieldUnit::new(Some("FLD3"), 4);
let elem5 = AmlFieldUnit::new(Some("FLD4"), 12);
for e in vec![elem1, elem2, elem3, elem4, elem5] {
field.append_child(e);
}
let target = vec![
0x5B, 0x81, 0x1C, 0x4F, 0x50, 0x52, 0x31, 0x41, 0x46, 0x4C, 0x44, 0x31, 0x08, 0x46,
0x4C, 0x44, 0x32, 0x08, 0x00, 0x08, 0x46, 0x4C, 0x44, 0x33, 0x04, 0x46, 0x4C, 0x44,
0x34, 0x0C,
];
assert_eq!(field.aml_bytes(), target);
}
#[test]
fn test_device() {
// Device (PCI0)
// {
// Name (_HID, EisaId ("PNP0A03"))
// }
let mut device = AmlDevice::new("PCI0");
let hid = AmlNameDecl::new("_HID", AmlEisaId::new("PNP0A03"));
device.append_child(hid);
let bytes = device.aml_bytes();
let target = vec![
0x5B, 0x82, 0x0F, 0x50, 0x43, 0x49, 0x30, 0x08, 0x5F, 0x48, 0x49, 0x44, 0x0C, 0x41,
0xD0, 0x0A, 0x03,
];
assert_eq!(bytes, target);
}
#[test]
fn test_scope() {
// Scope (_SB) {
// Name (INT1, 0xABCD)
// }
let mut scope = AmlScope::new("_SB");
scope.append_child(AmlNameDecl::new("INT1", AmlInteger(0xABCD)));
let target = vec![
0x10, 0x0D, 0x5F, 0x53, 0x42, 0x5F, 0x08, 0x49, 0x4E, 0x54, 0x31, 0x0B, 0xCD, 0xAB,
];
assert_eq!(scope.aml_bytes(), target);
}
#[test]
fn test_method() {
// Scope(\_SB.PCI4) {
// OperationRegion(LED1, SystemIO, 0x10C0, 0x20)
// Field(LED1, AnyAcc, NoLock, Preserve)
// { // LED controls
// S0LE, 1, // Slot 0 Ejection Progress LED
// S0LF, 1, // Slot 0 Ejection Failure LED
// S1LE, 1, // Slot 1 Ejection Progress LED
// S1LF, 1, // Slot 1 Ejection Failure LED
// S2LE, 1, // Slot 2 Ejection Progress LED
// S2LF, 1, // Slot 2 Ejection Failure LED
// S3LE, 1, // Slot 3 Ejection Progress LED
// S3LF, 1 // Slot 3 Ejection Failure LED
// }
// Device(SLT3) { // hot plug device
// Name(_ADR, 0x000C0003)
// Method(_OST, 3, Serialized) {
// If(LEqual(Arg0,Ones)) // Unspecified event
// {
// Store(Zero, Arg1)
// }
// Store(Zero, Arg2) // Turn off Ejection Progress LED
// Store(One, Arg0) // Turn on Ejection Failure LED
// }
// }
// }
let mut scope1 = AmlScope::new("\\_SB.PCI4");
let op_region = AmlOpRegion::new("LED1", AmlAddressSpaceType::SystemIO, 0x10C0, 0x20);
let mut field = AmlField::new(
"LED1",
AmlFieldAccessType::Any,
AmlFieldLockRule::NoLock,
AmlFieldUpdateRule::Preserve,
);
let mut elems = Vec::new();
elems.push(AmlFieldUnit::new(Some("S0LE"), 1));
elems.push(AmlFieldUnit::new(Some("S0LF"), 1));
elems.push(AmlFieldUnit::new(Some("S1LE"), 1));
elems.push(AmlFieldUnit::new(Some("S1LF"), 1));
elems.push(AmlFieldUnit::new(Some("S2LE"), 1));
elems.push(AmlFieldUnit::new(Some("S2LF"), 1));
elems.push(AmlFieldUnit::new(Some("S3LE"), 1));
elems.push(AmlFieldUnit::new(Some("S3LF"), 1));
for e in elems {
field.append_child(e);
}
let mut device = AmlDevice::new("SLT3");
let name1 = AmlNameDecl::new("_ADR", AmlInteger(0x000C0003));
let mut method1 = AmlMethod::new("_OST", 3, true);
let mut if_scope = AmlIf::new(AmlEqual::new(AmlArg(0), AmlOnes));
let store1 = AmlStore::new(AmlZero, AmlArg(1));
if_scope.append_child(store1);
let store2 = AmlStore::new(AmlZero, AmlArg(2));
let store3 = AmlStore::new(AmlOne, AmlArg(0));
method1.append_child(if_scope);
method1.append_child(store2);
method1.append_child(store3);
device.append_child(name1);
device.append_child(method1);
scope1.append_child(op_region);
scope1.append_child(field);
scope1.append_child(device);
let scope1_bytes = vec![
0x10, 0x4E, 0x06, 0x5C, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49, 0x34, 0x5B,
0x80, 0x4C, 0x45, 0x44, 0x31, 0x01, 0x0B, 0xC0, 0x10, 0x0A, 0x20, 0x5B, 0x81, 0x2E,
0x4C, 0x45, 0x44, 0x31, 0x00, 0x53, 0x30, 0x4C, 0x45, 0x01, 0x53, 0x30, 0x4C, 0x46,
0x01, 0x53, 0x31, 0x4C, 0x45, 0x01, 0x53, 0x31, 0x4C, 0x46, 0x01, 0x53, 0x32, 0x4C,
0x45, 0x01, 0x53, 0x32, 0x4C, 0x46, 0x01, 0x53, 0x33, 0x4C, 0x45, 0x01, 0x53, 0x33,
0x4C, 0x46, 0x01, 0x5B, 0x82, 0x24, 0x53, 0x4C, 0x54, 0x33, 0x08, 0x5F, 0x41, 0x44,
0x52, 0x0C, 0x03, 0x00, 0x0C, 0x00, 0x14, 0x14, 0x5F, 0x4F, 0x53, 0x54, 0x0B, 0xA0,
0x07, 0x93, 0x68, 0xFF, 0x70, 0x00, 0x69, 0x70, 0x00, 0x6A, 0x70, 0x01, 0x68,
];
assert_eq!(scope1.aml_bytes(), scope1_bytes);
// Scope (\_GPE)
// {
// Method(_E13)
// {
// Store(One, \_SB.PCI4.S3LE) // Turn on ejection request LED
// Notify(\_SB.PCI4.SLT3, 3) // Ejection request driven from GPE13
// }
// }
let mut scope2 = AmlScope::new("\\_GPE");
let mut method2 = AmlMethod::new("_E13", 0, false);
let store4 = AmlStore::new(AmlOne, AmlName("\\_SB.PCI4.S3LE".to_string()));
let notify = AmlNotify::new(AmlName("\\_SB.PCI4.SLT3".to_string()), AmlInteger(3));
method2.append_child(store4);
method2.append_child(notify);
scope2.append_child(method2);
let scope2_bytes = vec![
0x10, 0x30, 0x5C, 0x5F, 0x47, 0x50, 0x45, 0x14, 0x29, 0x5F, 0x45, 0x31, 0x33, 0x00,
0x70, 0x01, 0x5C, 0x2F, 0x03, 0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49, 0x34, 0x53,
0x33, 0x4C, 0x45, 0x86, 0x5C, 0x2F, 0x03, 0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49,
0x34, 0x53, 0x4C, 0x54, 0x33, 0x0A, 0x03,
];
assert_eq!(scope2.aml_bytes(), scope2_bytes);
}
#[test]
fn test_arithmetic_ops() {
// Method(INCR, 3) {
// If (Arg1 == Arg2) {
// Return
// }
// Local0 = Arg0
// While (Local0 < Arg1) {
// Local0++;
// }
// Local0--;
// Local0 += 2;
// If (Local0 > Arg2) {
// Local0 -= Arg2;
// }
// }
let mut method1 = AmlMethod::new("INCR", 3, false);
let mut if_scope1 = AmlIf::new(AmlEqual::new(AmlArg(1), AmlArg(2)));
if_scope1.append_child(AmlReturn::new());
method1.append_child(if_scope1);
let store1 = AmlStore::new(AmlArg(0), AmlLocal(0).clone());
method1.append_child(store1);
let mut while_scope = AmlWhile::new(AmlLLess::new(AmlLocal(0), AmlArg(1)));
while_scope.append_child(AmlIncrement::new(AmlLocal(0)));
method1.append_child(while_scope);
method1.append_child(AmlDecrement::new(AmlLocal(0)));
method1.append_child(AmlAdd::new(AmlLocal(0), AmlInteger(2), AmlLocal(0)));
let mut if_scope2 = AmlIf::new(AmlLGreater::new(AmlLocal(0), AmlArg(2)));
if_scope2.append_child(AmlSubtract::new(AmlLocal(0), AmlArg(2), AmlLocal(0)));
method1.append_child(if_scope2);
let method1_bytes = vec![
0x14, 0x27, 0x49, 0x4E, 0x43, 0x52, 0x03, 0xA0, 0x06, 0x93, 0x69, 0x6A, 0xA4, 0x00,
0x70, 0x68, 0x60, 0xA2, 0x06, 0x95, 0x60, 0x69, 0x75, 0x60, 0x76, 0x60, 0x72, 0x60,
0x0A, 0x02, 0x60, 0xA0, 0x08, 0x94, 0x60, 0x6A, 0x74, 0x60, 0x6A, 0x60,
];
assert_eq!(method1.aml_bytes(), method1_bytes);
// Method(MTD2, 1) {
// Local0 = SizeOf(Arg0)
// Name (PKG1, Package () {
// 0x01, 0x03F8, 0x03FF
// })
//
// Name (PKG2, Package(2){0x1234, "Hello world"})
//
// Store (DeRefOf (Index (PKG1, 5)), Local0)
// Concatenate(PKG1, PKG2, Local1)
//
// Return(Local0)
// }
let mut method2 = AmlMethod::new("MTD2", 1, false);
let store2 = AmlStore::new(AmlSizeOf::new(AmlArg(0)), AmlLocal(0));
method2.append_child(store2);
let mut pkg1 = AmlPackage::new(3);
vec![0x01, 0x03F8, 0x03FF].iter().for_each(|&x| {
pkg1.append_child(AmlInteger(x as u64));
});
let named_pkg1 = AmlNameDecl::new("PKG1", pkg1);
method2.append_child(named_pkg1);
let mut pkg2 = AmlPackage::new(2);
pkg2.append_child(AmlInteger(0x1234));
pkg2.append_child(AmlString("Hello world".to_string()));
let named_pkg2 = AmlNameDecl::new("PKG2", pkg2);
method2.append_child(named_pkg2);
let pkg1_str = AmlName("PKG1".to_string());
let pkg2_str = AmlName("PKG2".to_string());
let store3 = AmlStore::new(
AmlDeRefOf::new(AmlIndex::new(pkg1_str.clone(), AmlInteger(5), AmlZero)),
AmlLocal(0),
);
let concat = AmlConcat::new(pkg1_str, pkg2_str, AmlLocal(1));
method2.append_child(store3);
method2.append_child(concat);
let return_value = AmlReturn::with_value(AmlLocal(0));
method2.append_child(return_value);
let method2_bytes = vec![
0x14, 0x49, 0x04, 0x4D, 0x54, 0x44, 0x32, 0x01, 0x70, 0x87, 0x68, 0x60, 0x08, 0x50,
0x4B, 0x47, 0x31, 0x12, 0x09, 0x03, 0x01, 0x0B, 0xF8, 0x03, 0x0B, 0xFF, 0x03, 0x08,
0x50, 0x4B, 0x47, 0x32, 0x12, 0x12, 0x02, 0x0B, 0x34, 0x12, 0x0D, 0x48, 0x65, 0x6C,
0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x00, 0x70, 0x83, 0x88, 0x50, 0x4B,
0x47, 0x31, 0x0A, 0x05, 0x00, 0x60, 0x73, 0x50, 0x4B, 0x47, 0x31, 0x50, 0x4B, 0x47,
0x32, 0x61, 0xA4, 0x60,
];
assert_eq!(method2.aml_bytes(), method2_bytes);
}
#[test]
fn test_logical_ops() {
// Method(MTD3, 1) {
// Local0 = Arg0
//
// Local1 = (Local0 << 3) | 0xFF
// Local2 = (Local0 >> 3) & 0xFF
//
// If (Local1 && Local2) {
// Return(2)
// }
//
// if (Local1 || Local2) {
// Return(1)
// }
//
// Return(0)
// }
let mut method = AmlMethod::new("MTD3", 1, false);
let store1 = AmlStore::new(AmlArg(0), AmlLocal(0));
method.append_child(store1);
let shift_left = AmlShiftLeft::new(AmlLocal(0), AmlInteger(0x3), AmlZero);
let store2 = AmlOr::new(shift_left, AmlInteger(0xFF), AmlLocal(1));
method.append_child(store2);
let shift_right = AmlShiftRight::new(AmlLocal(0), AmlInteger(0x3), AmlZero);
let store3 = AmlAnd::new(shift_right, AmlInteger(0xFF), AmlLocal(2));
method.append_child(store3);
let mut if_scope1 = AmlIf::new(AmlLAnd::new(AmlLocal(1), AmlLocal(2)));
if_scope1.append_child(AmlReturn::with_value(AmlInteger(2)));
method.append_child(if_scope1);
let mut if_scope2 = AmlIf::new(AmlLOr::new(AmlLocal(1), AmlLocal(2)));
if_scope2.append_child(AmlReturn::with_value(AmlInteger(1)));
method.append_child(if_scope2);
method.append_child(AmlReturn::with_value(AmlInteger(0)));
let method_bytes = vec![
0x14, 0x2C, 0x4D, 0x54, 0x44, 0x33, 0x01, 0x70, 0x68, 0x60, 0x7D, 0x79, 0x60, 0x0A,
0x03, 0x00, 0x0A, 0xFF, 0x61, 0x7B, 0x7A, 0x60, 0x0A, 0x03, 0x00, 0x0A, 0xFF, 0x62,
0xA0, 0x07, 0x90, 0x61, 0x62, 0xA4, 0x0A, 0x02, 0xA0, 0x06, 0x91, 0x61, 0x62, 0xA4,
0x01, 0xA4, 0x00,
];
assert_eq!(method.aml_bytes(), method_bytes);
}
#[test]
fn test_mutex() {
// Device (PCI0)
// {
// Name (_HID, EisaId ("PNP0A03"))
// Mutex (MTX1, 0)
//
// Method(MTD1, 2) {
// Local0 = 0
// Local1 = Arg0
// while (Local0 < Local1) {
// Acquire(MTX1, 0xFFFF);
// Arg1 += 1
// Local0 += 1
// Release(MTX1)
// }
// }
// }
let mut device = AmlDevice::new("PCI0");
let hid = AmlNameDecl::new("_HID", AmlEisaId::new("PNP0A03"));
device.append_child(hid);
let mutex = AmlMutex::new("MTX1", 0);
device.append_child(mutex);
let mut method = AmlMethod::new("MTD1", 2, false);
let store1 = AmlStore::new(AmlInteger(0x0), AmlLocal(0));
let store2 = AmlStore::new(AmlArg(0), AmlLocal(1));
method.append_child(store1);
method.append_child(store2);
let mut while1 = AmlWhile::new(AmlLLess::new(AmlLocal(0), AmlLocal(1)));
while1.append_child(AmlAcquire::new(AmlName("MTX1".to_string()), 0xFFFF));
while1.append_child(AmlAdd::new(AmlArg(1), AmlInteger(1), AmlArg(1)));
while1.append_child(AmlAdd::new(AmlLocal(0), AmlInteger(1), AmlLocal(0)));
while1.append_child(AmlRelease::new(AmlName("MTX1".to_string())));
method.append_child(while1);
device.append_child(method);
let mutex_bytes = vec![
0x5B, 0x82, 0x3E, 0x50, 0x43, 0x49, 0x30, 0x08, 0x5F, 0x48, 0x49, 0x44, 0x0C, 0x41,
0xD0, 0x0A, 0x03, 0x5B, 0x01, 0x4D, 0x54, 0x58, 0x31, 0x00, 0x14, 0x27, 0x4D, 0x54,
0x44, 0x31, 0x02, 0x70, 0x00, 0x60, 0x70, 0x68, 0x61, 0xA2, 0x1A, 0x95, 0x60, 0x61,
0x5B, 0x23, 0x4D, 0x54, 0x58, 0x31, 0xFF, 0xFF, 0x72, 0x69, 0x01, 0x69, 0x72, 0x60,
0x01, 0x60, 0x5B, 0x27, 0x4D, 0x54, 0x58, 0x31,
];
assert_eq!(device.aml_bytes(), mutex_bytes);
}
#[test]
fn test_create_field() {
// Method(MTD1,1)
// {
// CreateDWordField (Arg0, 0, REVS)
// CreateDWordField (Arg0, 4, SIZE)
// CreateWordField (Arg0, 8, MINV)
// CreateQWordField (Arg0, 10, MAXV)
// CreateField (Arg0, 64, 8, TEMP)
//
// TEMP = MINV | MAXV
// Concatenate (REVS, SIZE, Local0)
//
// Return(Local0)
// }
let mut method = AmlMethod::new("MTD1", 1, false);
let revs = AmlCreateDWordField::new(AmlArg(0), AmlInteger(0), "REVS");
let size = AmlCreateDWordField::new(AmlArg(0), AmlInteger(4), "SIZE");
let minv = AmlCreateWordField::new(AmlArg(0), AmlInteger(8), "MINV");
let maxv = AmlCreateQWordField::new(AmlArg(0), AmlInteger(10), "MAXV");
let temp = AmlCreateField::new(AmlArg(0), AmlInteger(64), AmlInteger(8), "TEMP");
method.append_child(revs);
method.append_child(size);
method.append_child(minv);
method.append_child(maxv);
method.append_child(temp);
let store = AmlOr::new(
AmlName("MINV".to_string()),
AmlName("MAXV".to_string()),
AmlName("TEMP".to_string()),
);
let concat = AmlConcat::new(
AmlName("REVS".to_string()),
AmlName("SIZE".to_string()),
AmlLocal(0),
);
method.append_child(store);
method.append_child(concat);
method.append_child(AmlReturn::with_value(AmlLocal(0)));
let method_bytes = vec![
0x14, 0x4A, 0x04, 0x4D, 0x54, 0x44, 0x31, 0x01, 0x8A, 0x68, 0x00, 0x52, 0x45, 0x56,
0x53, 0x8A, 0x68, 0x0A, 0x04, 0x53, 0x49, 0x5A, 0x45, 0x8B, 0x68, 0x0A, 0x08, 0x4D,
0x49, 0x4E, 0x56, 0x8F, 0x68, 0x0A, 0x0A, 0x4D, 0x41, 0x58, 0x56, 0x5B, 0x13, 0x68,
0x0A, 0x40, 0x0A, 0x08, 0x54, 0x45, 0x4D, 0x50, 0x7D, 0x4D, 0x49, 0x4E, 0x56, 0x4D,
0x41, 0x58, 0x56, 0x54, 0x45, 0x4D, 0x50, 0x73, 0x52, 0x45, 0x56, 0x53, 0x53, 0x49,
0x5A, 0x45, 0x60, 0xA4, 0x60,
];
assert_eq!(method.aml_bytes(), method_bytes);
}
#[test]
fn test_res_template() {
// ResourceTemplate(){
// IO(Decode16, 0x62, 0x62, 0, 1)
// IO(Decode10, 0x66, 0x66, 0, 1)
// DMA(Compatibility, BusMaster, Transfer8_16) {0x3}
// Memory32Fixed(ReadOnly, 0xfed00000, 0x400)
// }
let io_res1 = AmlIoResource::new(AmlIoDecode::Decode16, 0x62, 0x62, 0, 0x1);
let io_res2 = AmlIoResource::new(AmlIoDecode::Decode10, 0x66, 0x66, 0, 0x1);
let dma_res = AmlDmaResource::new(
AmlDmaType::Compatibility,
true,
AmlDmaTransSize::Size8_16,
0x3,
);
let fixed_mem32 = AmlMemory32Fixed::new(AmlReadAndWrite::ReadOnly, 0xfed00000, 0x400);
let mut resource = AmlResTemplate::new();
resource.append_child(io_res1);
resource.append_child(io_res2);
resource.append_child(dma_res);
resource.append_child(fixed_mem32);
let target = vec![
0x11, 0x24, 0x0A, 0x21, 0x47, 0x01, 0x62, 0x00, 0x62, 0x00, 0x00, 0x01, 0x47, 0x00,
0x66, 0x00, 0x66, 0x00, 0x00, 0x01, 0x2A, 0x08, 0x05, 0x86, 0x09, 0x00, 0x00, 0x00,
0x00, 0xD0, 0xFE, 0x00, 0x04, 0x00, 0x00, 0x79, 0x00,
];
assert_eq!(resource.aml_bytes(), target);
}
#[test]
fn test_interrupt() {
// ResourceTemplate ()
// {
// Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) {41}
// Interrupt(ResourceConsumer, Edge, ActiveHigh, Shared) {42}
// Interrupt(ResourceProducer, Level, ActiveHigh, ExclusiveAndWake) {43}
// IRQNoFlags(INT4) {7}
// }
let mut resource = AmlResTemplate::new();
let int1 = AmlExtendedInterrupt::new(
AmlResourceUsage::Consumer,
AmlEdgeLevel::Level,
AmlActiveLevel::High,
AmlIntShare::Exclusive,
vec![41],
);
let int2 = AmlExtendedInterrupt::new(
AmlResourceUsage::Consumer,
AmlEdgeLevel::Edge,
AmlActiveLevel::High,
AmlIntShare::Share,
vec![42],
);
let int3 = AmlExtendedInterrupt::new(
AmlResourceUsage::Producer,
AmlEdgeLevel::Level,
AmlActiveLevel::High,
AmlIntShare::ExclusiveWake,
vec![43],
);
let int4 = AmlIrqNoFlags::new(7);
resource.append_child(int1);
resource.append_child(int2);
resource.append_child(int3);
resource.append_child(int4);
let res_bytes = vec![
0x11, 0x23, 0x0A, 0x20, 0x89, 0x06, 0x00, 0x01, 0x01, 0x29, 0x00, 0x00, 0x00, 0x89,
0x06, 0x00, 0x0B, 0x01, 0x2A, 0x00, 0x00, 0x00, 0x89, 0x06, 0x00, 0x10, 0x01, 0x2B,
0x00, 0x00, 0x00, 0x22, 0x80, 0x00, 0x79, 0x00,
];
assert_eq!(resource.aml_bytes(), res_bytes);
}
#[test]
fn test_res_template_64() {
// ResourceTemplate(){
// QWordMemory(ResourceConsumer, SubDecode, MinFixed, MaxFixed,
// WriteCombining, ReadOnly, 0x0, 0x0, 0x7FFFFFFFFF, 0x0, 0x8000000000)
// DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed,
// Prefetchable, ReadWrite, 0x0, 0x0, 0xFFFFFFFE, 0x0, 0xFFFFFFFF)
// WordBusNumber(ResourceProducer, MinFixed, MaxFixed, PosDecode,
// 0x0, 0x0, 0xFFFC, 0xAAAA, 0xFFFD)
// DWordIO(ResourceConsumer, MinFixed, MaxFixed, SubDecode,
// EntireRange, 0x0, 0x0, 0xFFFF, 0x3eff0000, 0x00010000)
// WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode,
// EntireRange, 0x0, 0x0, 0x0CF7, 0x0, 0x0CF8)
// }
let q_mem = AmlQWordDesc::new_memory(
AmlAddressSpaceDecode::Subtract,
AmlCacheable::WriteCombining,
AmlReadAndWrite::ReadOnly,
0x0,
0x0,
0x7FFFFFFFFF,
0x0,
0x8000000000,
);
let d_mem = AmlDWordDesc::new_memory(
AmlAddressSpaceDecode::Positive,
AmlCacheable::Prefetchable,
AmlReadAndWrite::ReadWrite,
0x0,
0x0,
0xFFFFFFFE,
0x0,
0xFFFFFFFF,
);
let bus_num = AmlWordDesc::new_bus_number(
AmlAddressSpaceDecode::Positive,
0x0,
0x0,
0xFFFC,
0xAAAA,
0xFFFD,
);
let d_io = AmlDWordDesc::new_io(
AmlAddressSpaceDecode::Subtract,
AmlISARanges::EntireRange,
0x0,
0x0,
0xFFFF,
0x3eff0000,
0x00010000,
);
let w_io = AmlWordDesc::new_io(
AmlAddressSpaceDecode::Positive,
AmlISARanges::EntireRange,
0x0,
0x0,
0x0CF7,
0x0,
0x0CF8,
);
let mut resource = AmlResTemplate::new();
resource.append_child(q_mem);
resource.append_child(d_mem);
resource.append_child(bus_num);
resource.append_child(d_io);
resource.append_child(w_io);
let target = vec![
0x11, 0x48, 0x08, 0x0A, 0x84, 0x8A, 0x2B, 0x00, 0x00, 0x0E, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x87, 0x17, 0x00, 0x00, 0x0C,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x00, 0x02, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFC, 0xFF, 0xAA, 0xAA, 0xFD, 0xFF, 0x87, 0x17, 0x00, 0x01, 0x0E,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x88, 0x0D, 0x00, 0x01, 0x0C, 0x03, 0x00,
0x00, 0x00, 0x00, 0xF7, 0x0C, 0x00, 0x00, 0xF8, 0x0C, 0x79, 0x00,
];
assert_eq!(resource.aml_bytes(), target);
}
}

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/openeuler-stratovirt.git
git@gitlife.ru:oschina-mirror/openeuler-stratovirt.git
oschina-mirror
openeuler-stratovirt
openeuler-stratovirt
v2.2.0-rc2