Skip to content

Commit 4ce1dad

Browse files
committed
AML: implement ToString, ToBuffer, ToDecimalString, ToHexString, and ToInteger
1 parent 3956699 commit 4ce1dad

File tree

2 files changed

+154
-10
lines changed

2 files changed

+154
-10
lines changed

src/aml/mod.rs

Lines changed: 149 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,12 @@ where
327327
| Opcode::LLess => {
328328
self.do_logical_op(&mut context, op)?;
329329
}
330-
Opcode::ToBuffer
331-
| Opcode::ToDecimalString
332-
| Opcode::ToHexString
333-
| Opcode::ToInteger
334-
| Opcode::ToString => todo!(),
330+
Opcode::ToBuffer => self.do_to_buffer(&mut context, op)?,
331+
Opcode::ToInteger => self.do_to_integer(&mut context, op)?,
332+
Opcode::ToString => self.do_to_string(&mut context, op)?,
333+
Opcode::ToDecimalString | Opcode::ToHexString => {
334+
self.do_to_dec_hex_string(&mut context, op)?
335+
}
335336
Opcode::Mid => self.do_mid(&mut context, op)?,
336337
Opcode::Concat => self.do_concat(&mut context, op)?,
337338
Opcode::ConcatRes => {
@@ -1202,11 +1203,10 @@ where
12021203
context.start_in_flight_op(OpInFlight::new(opcode, 2));
12031204
}
12041205

1205-
Opcode::ToBuffer
1206-
| Opcode::ToDecimalString
1207-
| Opcode::ToHexString
1208-
| Opcode::ToInteger
1209-
| Opcode::ToString => context.start_in_flight_op(OpInFlight::new(opcode, 2)),
1206+
Opcode::ToBuffer | Opcode::ToDecimalString | Opcode::ToHexString | Opcode::ToInteger => {
1207+
context.start_in_flight_op(OpInFlight::new(opcode, 2))
1208+
}
1209+
Opcode::ToString => context.start_in_flight_op(OpInFlight::new(opcode, 3)),
12101210

12111211
Opcode::ObjectType => context.start_in_flight_op(OpInFlight::new(opcode, 1)),
12121212
Opcode::CopyObject => todo!(),
@@ -1485,6 +1485,140 @@ where
14851485
Ok(())
14861486
}
14871487

1488+
fn do_to_buffer(&self, context: &mut MethodContext, op: OpInFlight) -> Result<(), AmlError> {
1489+
let [Argument::Object(operand), target] = &op.arguments[..] else { panic!() };
1490+
1491+
let result = Arc::new(match **operand {
1492+
Object::Buffer(ref bytes) => Object::Buffer(bytes.clone()),
1493+
Object::Integer(value) => {
1494+
if self.dsdt_revision >= 2 {
1495+
Object::Buffer(value.to_le_bytes().to_vec())
1496+
} else {
1497+
Object::Buffer((value as u32).to_le_bytes().to_vec())
1498+
}
1499+
}
1500+
Object::String(ref value) => {
1501+
// XXX: an empty string is converted to an empty buffer, *without* the null-terminator
1502+
if value.is_empty() {
1503+
Object::Buffer(vec![])
1504+
} else {
1505+
let mut bytes = value.as_bytes().to_vec();
1506+
bytes.push(b'\0');
1507+
Object::Buffer(bytes)
1508+
}
1509+
}
1510+
_ => Err(AmlError::InvalidOperationOnObject { op: Operation::ToBuffer, typ: operand.typ() })?,
1511+
});
1512+
1513+
// TODO: use result of store
1514+
self.do_store(target, result.clone())?;
1515+
context.contribute_arg(Argument::Object(result));
1516+
Ok(())
1517+
}
1518+
1519+
fn do_to_integer(&self, context: &mut MethodContext, op: OpInFlight) -> Result<(), AmlError> {
1520+
let [Argument::Object(operand), target] = &op.arguments[..] else { panic!() };
1521+
1522+
let result = Arc::new(match **operand {
1523+
Object::Integer(value) => Object::Integer(value),
1524+
Object::Buffer(ref bytes) => {
1525+
/*
1526+
* The spec says this should respect the revision of the current definition block.
1527+
* Apparently, the NT interpreter always uses the first 8 bytes of the buffer.
1528+
*/
1529+
let mut to_interpret = [0u8; 8];
1530+
(to_interpret[0..usize::min(bytes.len(), 8)]).copy_from_slice(&bytes);
1531+
Object::Integer(u64::from_le_bytes(to_interpret))
1532+
}
1533+
Object::String(ref value) => {
1534+
if let Some(value) = value.strip_prefix("0x") {
1535+
let parsed = u64::from_str_radix(value, 16).map_err(|_| {
1536+
AmlError::InvalidOperationOnObject { op: Operation::ToInteger, typ: ObjectType::String }
1537+
})?;
1538+
Object::Integer(parsed)
1539+
} else {
1540+
let parsed = u64::from_str_radix(value, 10).map_err(|_| {
1541+
AmlError::InvalidOperationOnObject { op: Operation::ToInteger, typ: ObjectType::String }
1542+
})?;
1543+
Object::Integer(parsed)
1544+
}
1545+
}
1546+
_ => Err(AmlError::InvalidOperationOnObject { op: Operation::ToBuffer, typ: operand.typ() })?,
1547+
});
1548+
1549+
// TODO: use result of store
1550+
self.do_store(target, result.clone())?;
1551+
context.contribute_arg(Argument::Object(result));
1552+
Ok(())
1553+
}
1554+
1555+
fn do_to_string(&self, context: &mut MethodContext, op: OpInFlight) -> Result<(), AmlError> {
1556+
let [Argument::Object(source), Argument::Object(length), target] = &op.arguments[..] else { panic!() };
1557+
let source = source.as_buffer()?;
1558+
let length = length.as_integer()? as usize;
1559+
1560+
let result = Arc::new(if source.is_empty() {
1561+
Object::String(String::new())
1562+
} else {
1563+
let mut buffer = source.split_inclusive(|b| *b == b'\0').next().unwrap();
1564+
if length < usize::MAX {
1565+
buffer = &buffer[0..usize::min(length, buffer.len())];
1566+
}
1567+
let string = str::from_utf8(buffer).map_err(|_| AmlError::InvalidOperationOnObject {
1568+
op: Operation::ToString,
1569+
typ: ObjectType::Buffer,
1570+
})?;
1571+
Object::String(string.to_string())
1572+
});
1573+
1574+
// TODO: use result of store
1575+
self.do_store(target, result.clone())?;
1576+
context.contribute_arg(Argument::Object(result));
1577+
Ok(())
1578+
}
1579+
1580+
/// Perform a `ToDecimalString` or `ToHexString` operation
1581+
fn do_to_dec_hex_string(&self, context: &mut MethodContext, op: OpInFlight) -> Result<(), AmlError> {
1582+
let [Argument::Object(operand), target] = &op.arguments[..] else { panic!() };
1583+
let operand = operand.clone().unwrap_transparent_reference();
1584+
1585+
let result = Arc::new(match *operand {
1586+
Object::String(ref value) => Object::String(value.clone()),
1587+
Object::Integer(value) => match op.op {
1588+
Opcode::ToDecimalString => Object::String(value.to_string()),
1589+
Opcode::ToHexString => Object::String(alloc::format!("{:#x}", value)),
1590+
_ => panic!(),
1591+
},
1592+
Object::Buffer(ref bytes) => {
1593+
if bytes.is_empty() {
1594+
Object::String(String::new())
1595+
} else {
1596+
// TODO: there has GOT to be a better way to format directly into a string...
1597+
let mut string = String::new();
1598+
for byte in bytes {
1599+
let as_str = match op.op {
1600+
Opcode::ToDecimalString => alloc::format!("{},", byte),
1601+
Opcode::ToHexString => alloc::format!("{:?},", byte),
1602+
_ => panic!(),
1603+
};
1604+
string.push_str(&as_str);
1605+
}
1606+
// Remove last comma, if present
1607+
if !string.is_empty() {
1608+
string.pop();
1609+
}
1610+
Object::String(string)
1611+
}
1612+
}
1613+
_ => Err(AmlError::InvalidOperationOnObject { op: Operation::ToDecOrHexString, typ: operand.typ() })?,
1614+
});
1615+
1616+
// TODO: use result of store
1617+
self.do_store(target, result.clone())?;
1618+
context.contribute_arg(Argument::Object(result));
1619+
Ok(())
1620+
}
1621+
14881622
fn do_mid(&self, context: &mut MethodContext, op: OpInFlight) -> Result<(), AmlError> {
14891623
let [Argument::Object(source), Argument::Object(index), Argument::Object(length), target] =
14901624
&op.arguments[..]
@@ -2572,6 +2706,11 @@ pub enum Operation {
25722706
Release,
25732707
ConvertToBuffer,
25742708

2709+
ToBuffer,
2710+
ToInteger,
2711+
ToString,
2712+
ToDecOrHexString,
2713+
25752714
ReadBufferField,
25762715
WriteBufferField,
25772716
LogicalOp,

tools/aml_tester/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use acpi::aml::{namespace::AmlName, AmlError, Handle, Interpreter};
1313
use clap::{Arg, ArgAction, ArgGroup};
14+
use log::info;
1415
use pci_types::PciAddress;
1516
use std::{
1617
collections::HashSet,
@@ -401,6 +402,10 @@ impl acpi::aml::Handler for Handler {
401402
println!("write_pci_u32 ({address})<-{value}");
402403
}
403404

405+
fn handle_debug(&self, object: &acpi::aml::object::Object) {
406+
info!("Debug store: {:?}", object);
407+
}
408+
404409
fn nanos_since_boot(&self) -> u64 {
405410
0
406411
}

0 commit comments

Comments
 (0)