mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
acpi: add helper method to pretty-print AML object trees
This commit is contained in:
parent
fe6c8f7293
commit
9dd9ab9add
@ -1,5 +1,11 @@
|
|||||||
package aml
|
package aml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"gopheros/kernel/kfmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// InvalidIndex is a sentinel value used by ObjectTree to indicate that
|
// InvalidIndex is a sentinel value used by ObjectTree to indicate that
|
||||||
// a returned object index is not valid.
|
// a returned object index is not valid.
|
||||||
@ -396,3 +402,197 @@ func (tree *ObjectTree) ArgAt(obj *Object, index uint32) *Object {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrettyPrint outputs a pretty-printed version of the AML tree to w.
|
||||||
|
func (tree *ObjectTree) PrettyPrint(w io.Writer) {
|
||||||
|
if len(tree.objPool) != 0 {
|
||||||
|
var padBuf bytes.Buffer
|
||||||
|
padBuf.WriteByte(' ')
|
||||||
|
tree.toString(w, &padBuf, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tree *ObjectTree) toString(w io.Writer, padBuf *bytes.Buffer, index uint32) {
|
||||||
|
curObj := tree.ObjectAt(index)
|
||||||
|
|
||||||
|
_, _ = w.Write(padBuf.Bytes())
|
||||||
|
kfmt.Fprintf(w, "+- [%s", pOpcodeName(curObj.opcode))
|
||||||
|
|
||||||
|
if name := nameOf(curObj); len(name) != 0 {
|
||||||
|
kfmt.Fprintf(w, ", name: \"%s\"", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if curObj.opcode == pOpMethod {
|
||||||
|
kfmt.Fprintf(w, ", argCount: %d", uint8(tree.ArgAt(curObj, 1).value.(uint64)&0x7))
|
||||||
|
}
|
||||||
|
|
||||||
|
kfmt.Fprintf(w, ", table: %d, index: %d, offset: 0x%x", curObj.tableHandle, curObj.index, curObj.amlOffset)
|
||||||
|
kfmt.Fprintf(w, "]")
|
||||||
|
|
||||||
|
if curObj.opcode == pOpIntMethodCall {
|
||||||
|
methodObj := tree.ObjectAt(curObj.value.(uint32))
|
||||||
|
argCount := uint8(tree.ArgAt(methodObj, 1).value.(uint64) & 0x7)
|
||||||
|
kfmt.Fprintf(w, " -> [call to \"%s\", argCount: %d, table: %d, index: %d, offset: 0x%x]", methodObj.name[:], argCount, methodObj.tableHandle, methodObj.index, methodObj.amlOffset)
|
||||||
|
} else if curObj.opcode == pOpIntResolvedNamePath {
|
||||||
|
resolvedObj := tree.ObjectAt(curObj.value.(uint32))
|
||||||
|
kfmt.Fprintf(w, " -> [resolved to \"%s\", table: %d, index: %d, offset: 0x%x]", nameOf(resolvedObj), resolvedObj.tableHandle, resolvedObj.index, resolvedObj.amlOffset)
|
||||||
|
} else if curObj.opcode == pOpIntNamedField {
|
||||||
|
field := curObj.value.(*fieldElement)
|
||||||
|
kfmt.Fprintf(w, " -> [field index: %d, offset(bytes): 0x%x, width(bits): 0x%x, accType: ", field.fieldIndex, field.offset, field.width)
|
||||||
|
switch field.accessType {
|
||||||
|
case 0x00:
|
||||||
|
kfmt.Fprintf(w, "Any")
|
||||||
|
case 0x01:
|
||||||
|
kfmt.Fprintf(w, "Byte")
|
||||||
|
case 0x02:
|
||||||
|
kfmt.Fprintf(w, "Word")
|
||||||
|
case 0x03:
|
||||||
|
kfmt.Fprintf(w, "Dword")
|
||||||
|
case 0x04:
|
||||||
|
kfmt.Fprintf(w, "Qword")
|
||||||
|
case 0x05:
|
||||||
|
kfmt.Fprintf(w, "Buffer, accAttr: ")
|
||||||
|
switch field.accessAttrib {
|
||||||
|
case 0x02:
|
||||||
|
kfmt.Fprintf(w, "Quick")
|
||||||
|
case 0x04:
|
||||||
|
kfmt.Fprintf(w, "SendReceive")
|
||||||
|
case 0x06:
|
||||||
|
kfmt.Fprintf(w, "Byte")
|
||||||
|
case 0x08:
|
||||||
|
kfmt.Fprintf(w, "Word")
|
||||||
|
case 0x0a:
|
||||||
|
kfmt.Fprintf(w, "Block")
|
||||||
|
case 0x0b:
|
||||||
|
kfmt.Fprintf(w, "Bytes(0x%x)", field.accessLength)
|
||||||
|
case 0x0c:
|
||||||
|
kfmt.Fprintf(w, "ProcessCall")
|
||||||
|
case 0x0d:
|
||||||
|
kfmt.Fprintf(w, "BlockProcessCall")
|
||||||
|
case 0x0e:
|
||||||
|
kfmt.Fprintf(w, "RawBytes(0x%x)", field.accessLength)
|
||||||
|
case 0x0f:
|
||||||
|
kfmt.Fprintf(w, "RawProcessBytes(0x%x)", field.accessLength)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
case 0x40:
|
||||||
|
kfmt.Fprintf(w, "Bytes(0x%x)", field.AccessAttrib)
|
||||||
|
case 0x80:
|
||||||
|
kfmt.Fprintf(w, "RawBytes(0x%x)", field.AccessAttrib)
|
||||||
|
case 0xc0:
|
||||||
|
kfmt.Fprintf(w, "RawProcessBytes(0x%x)", field.AccessAttrib)
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
kfmt.Fprintf(w, ", lockType: ")
|
||||||
|
switch field.lockType {
|
||||||
|
case 0x00:
|
||||||
|
kfmt.Fprintf(w, "NoLock")
|
||||||
|
case 0x01:
|
||||||
|
kfmt.Fprintf(w, "Lock")
|
||||||
|
}
|
||||||
|
|
||||||
|
kfmt.Fprintf(w, ", updateType: ")
|
||||||
|
switch field.updateType {
|
||||||
|
case 0x00:
|
||||||
|
kfmt.Fprintf(w, "Preserve")
|
||||||
|
case 0x01:
|
||||||
|
kfmt.Fprintf(w, "WriteAsOnes")
|
||||||
|
case 0x02:
|
||||||
|
kfmt.Fprintf(w, "WriteAsZeroes")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch field.connectionIndex {
|
||||||
|
case InvalidIndex:
|
||||||
|
kfmt.Fprintf(w, ", connection: -]")
|
||||||
|
default:
|
||||||
|
kfmt.Fprintf(w, ", connection: index %d]", field.connectionIndex)
|
||||||
|
}
|
||||||
|
} else if curObj.opcode == pOpStringPrefix {
|
||||||
|
kfmt.Fprintf(w, " -> [string value: \"%s\"]", curObj.value.([]byte))
|
||||||
|
} else if curObj.opcode == pOpIntNamePath {
|
||||||
|
kfmt.Fprintf(w, " -> [namepath: \"%s\"]", curObj.value.([]byte))
|
||||||
|
} else if curObj.value != nil {
|
||||||
|
switch v := curObj.value.(type) {
|
||||||
|
case uint64:
|
||||||
|
kfmt.Fprintf(w, " -> [num value; dec: %d, hex: 0x%x]", v, v)
|
||||||
|
|
||||||
|
// If this is an encoded EISA id convert it back to a string
|
||||||
|
if curObj.opcode == pOpDwordPrefix && tree.ObjectAt(curObj.parentIndex).name == [amlNameLen]byte{'_', 'H', 'I', 'D'} {
|
||||||
|
// Poor-man's ntohl
|
||||||
|
id := uint32((v>>24)&0xff) |
|
||||||
|
uint32((v>>16)&0xff)<<8 |
|
||||||
|
uint32((v>>8)&0xff)<<16 |
|
||||||
|
uint32(v&0xff)<<24
|
||||||
|
|
||||||
|
var eisaID = [7]byte{
|
||||||
|
'@' + (byte)((id>>26)&0x1f),
|
||||||
|
'@' + (byte)((id>>21)&0x1f),
|
||||||
|
'@' + (byte)((id>>16)&0x1f),
|
||||||
|
hexToASCII(id >> 12),
|
||||||
|
hexToASCII(id >> 8),
|
||||||
|
hexToASCII(id >> 4),
|
||||||
|
hexToASCII(id),
|
||||||
|
}
|
||||||
|
|
||||||
|
kfmt.Fprintf(w, " [EISA: \"%s\"]", eisaID[:])
|
||||||
|
}
|
||||||
|
case []byte:
|
||||||
|
|
||||||
|
kfmt.Fprintf(w, " -> [bytelist value; len: %d; data: [", len(v))
|
||||||
|
for i, b := range v {
|
||||||
|
if i != 0 {
|
||||||
|
kfmt.Fprintf(w, ", ")
|
||||||
|
}
|
||||||
|
kfmt.Fprintf(w, "0x%x", uint8(b))
|
||||||
|
}
|
||||||
|
kfmt.Fprintf(w, "]]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kfmt.Fprintf(w, "\n")
|
||||||
|
|
||||||
|
padLen := padBuf.Len()
|
||||||
|
if curObj.nextSiblingIndex == InvalidIndex {
|
||||||
|
padBuf.WriteByte(' ')
|
||||||
|
} else {
|
||||||
|
padBuf.WriteByte('|')
|
||||||
|
}
|
||||||
|
padBuf.WriteByte(' ')
|
||||||
|
padBuf.WriteByte(' ')
|
||||||
|
|
||||||
|
for argIndex := curObj.firstArgIndex; argIndex != InvalidIndex; argIndex = tree.ObjectAt(argIndex).nextSiblingIndex {
|
||||||
|
tree.toString(w, padBuf, argIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
padBuf.Truncate(padLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexToASCII(val uint32) byte {
|
||||||
|
v := byte(val & 0xf)
|
||||||
|
if v <= 9 {
|
||||||
|
return '0' + v
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'A' + (v - 0xa)
|
||||||
|
}
|
||||||
|
|
||||||
|
func nameOf(obj *Object) []byte {
|
||||||
|
var nameStartIndex, nameEndIndex int
|
||||||
|
for ; nameStartIndex < amlNameLen; nameStartIndex++ {
|
||||||
|
if ch := obj.name[nameStartIndex]; (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '\\' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for nameEndIndex = nameStartIndex; nameEndIndex < amlNameLen; nameEndIndex++ {
|
||||||
|
if ch := obj.name[nameEndIndex]; !((ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '\\') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nameStartIndex != amlNameLen {
|
||||||
|
return obj.name[nameStartIndex:nameEndIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user