mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
600 lines
18 KiB
Go
600 lines
18 KiB
Go
package aml
|
||
|
||
import (
|
||
"bytes"
|
||
"gopheros/kernel/kfmt"
|
||
"io"
|
||
)
|
||
|
||
const (
|
||
// InvalidIndex is a sentinel value used by ObjectTree to indicate that
|
||
// a returned object index is not valid.
|
||
InvalidIndex uint32 = (1 << 32) - 1
|
||
|
||
// The size of AML name identifiers in bytes.
|
||
amlNameLen = 4
|
||
)
|
||
|
||
// fieldElement groups together information about a field element. This
|
||
// information can also be obtained by scanning a field element's siblings but
|
||
// it is summarized in this structure for convenience.
|
||
type fieldElement struct {
|
||
// The offset in the address space defined by parent field.
|
||
offset uint32
|
||
|
||
// The width of this field element in bits.
|
||
width uint32
|
||
|
||
accessLength uint8
|
||
_pad [3]uint8
|
||
|
||
accessType uint8
|
||
accessAttrib uint8
|
||
lockType uint8
|
||
updateType uint8
|
||
|
||
// The index of an Object to use as a connection target. Used only for
|
||
// GenericSerialBus and GeneralPurposeIO operation regions.
|
||
connectionIndex uint32
|
||
|
||
// The index of the Field (pOpField, pOpIndexField or pOpBankField) that this
|
||
// field element belongs to. According to the spec, named fields appear
|
||
// at the same scope as their parent.
|
||
fieldIndex uint32
|
||
}
|
||
|
||
// Object describes an entity encoded in the AML bytestream.
|
||
type Object struct {
|
||
// The AML ocode that describes this oBject.
|
||
opcode uint16
|
||
|
||
// The Index in the opcodeTable for this opcode
|
||
infoIndex uint8
|
||
|
||
// The table handle which contains this entity.
|
||
tableHandle uint8
|
||
|
||
// Named AML entities provide a fixed-width name which is padded by '_' chars.
|
||
name [amlNameLen]byte
|
||
|
||
// The following indices refer to other Objects in the ObjectTree
|
||
// that allocated this Object instance. Uninitialized indices are
|
||
// represented via a math.MaxUint32 value.
|
||
index uint32
|
||
parentIndex uint32
|
||
prevSiblingIndex uint32
|
||
nextSiblingIndex uint32
|
||
firstArgIndex uint32
|
||
lastArgIndex uint32
|
||
|
||
// The byte offset in the AML stream where this opcode is defined.
|
||
amlOffset uint32
|
||
|
||
// A non-zero value for pkgEnd indicates that this opcode requires deferred
|
||
// parsing due to its potentially ambiguous contents.
|
||
pkgEnd uint32
|
||
|
||
// A value placeholder for entites that contain values (e.g. int
|
||
// or string constants byte slices e.t.c)
|
||
value interface{}
|
||
}
|
||
|
||
// ObjectTree is a structure that contains a tree of AML entities where each
|
||
// entity is allocated from a contiguous Object pool. Index #0 of the pool
|
||
// contains the root scope ('\') of the AML tree.
|
||
type ObjectTree struct {
|
||
objPool []*Object
|
||
freeListHeadIndex uint32
|
||
}
|
||
|
||
// NewObjectTree returns a new ObjectTree instance.
|
||
func NewObjectTree() *ObjectTree {
|
||
return &ObjectTree{
|
||
freeListHeadIndex: InvalidIndex,
|
||
}
|
||
}
|
||
|
||
// CreateDefaultScopes populates the Object pool with the default scopes
|
||
// specified by the ACPI standard:
|
||
//
|
||
// +-[\] (Root scope)
|
||
// +- [_GPE] (General events in GPE register block)
|
||
// +- [_PR_] (ACPI 1.0 processor namespace)
|
||
// +- [_SB_] (System bus with all device objects)
|
||
// +- [_SI_] (System indicators)
|
||
// +- [_TZ_] (ACPI 1.0 thermal zone namespace)
|
||
func (tree *ObjectTree) CreateDefaultScopes(tableHandle uint8) {
|
||
root := tree.newNamedObject(pOpIntScopeBlock, tableHandle, [amlNameLen]byte{'\\'})
|
||
tree.append(root, tree.newNamedObject(pOpIntScopeBlock, tableHandle, [amlNameLen]byte{'_', 'G', 'P', 'E'})) // General events in GPE register block
|
||
tree.append(root, tree.newNamedObject(pOpIntScopeBlock, tableHandle, [amlNameLen]byte{'_', 'P', 'R', '_'})) // ACPI 1.0 processor namespace
|
||
tree.append(root, tree.newNamedObject(pOpIntScopeBlock, tableHandle, [amlNameLen]byte{'_', 'S', 'B', '_'})) // System bus with all device objects
|
||
tree.append(root, tree.newNamedObject(pOpIntScopeBlock, tableHandle, [amlNameLen]byte{'_', 'S', 'I', '_'})) // System indicators
|
||
tree.append(root, tree.newNamedObject(pOpIntScopeBlock, tableHandle, [amlNameLen]byte{'_', 'T', 'Z', '_'})) // ACPI 1.0 thermal zone namespace
|
||
}
|
||
|
||
// newObject allocates a new Object from the Object pool, populates its
|
||
// contents and returns back a pointer to it.
|
||
func (tree *ObjectTree) newObject(opcode uint16, tableHandle uint8) *Object {
|
||
var obj *Object
|
||
|
||
// Check the free list first
|
||
if tree.freeListHeadIndex != InvalidIndex {
|
||
obj = tree.objPool[tree.freeListHeadIndex]
|
||
tree.freeListHeadIndex = obj.nextSiblingIndex
|
||
} else {
|
||
// Allocate new object and attach it to the pool
|
||
obj = new(Object)
|
||
obj.index = uint32(len(tree.objPool))
|
||
tree.objPool = append(tree.objPool, obj)
|
||
}
|
||
|
||
obj.opcode = opcode
|
||
obj.infoIndex = pOpcodeTableIndex(opcode, true)
|
||
obj.tableHandle = tableHandle
|
||
obj.parentIndex = InvalidIndex
|
||
obj.prevSiblingIndex = InvalidIndex
|
||
obj.nextSiblingIndex = InvalidIndex
|
||
obj.firstArgIndex = InvalidIndex
|
||
obj.lastArgIndex = InvalidIndex
|
||
obj.value = nil
|
||
|
||
return obj
|
||
}
|
||
|
||
// newNamedObject allocates a new Object from the Object pool, populates its
|
||
// name and returns back a pointer to it.
|
||
func (tree *ObjectTree) newNamedObject(opcode uint16, tableHandle uint8, name [amlNameLen]byte) *Object {
|
||
obj := tree.newObject(opcode, tableHandle)
|
||
obj.name = name
|
||
return obj
|
||
}
|
||
|
||
// append appends arg to obj's argument list.
|
||
func (tree *ObjectTree) append(obj, arg *Object) {
|
||
arg.parentIndex = obj.index
|
||
|
||
if obj.lastArgIndex == InvalidIndex {
|
||
obj.firstArgIndex = arg.index
|
||
obj.lastArgIndex = arg.index
|
||
return
|
||
}
|
||
|
||
LastArg := tree.ObjectAt(obj.lastArgIndex)
|
||
LastArg.nextSiblingIndex = arg.index
|
||
arg.prevSiblingIndex = LastArg.index
|
||
arg.nextSiblingIndex = InvalidIndex
|
||
obj.lastArgIndex = arg.index
|
||
}
|
||
|
||
// appendAfter appends arg to obj's argument list after nextTo.
|
||
func (tree *ObjectTree) appendAfter(obj, arg, nextTo *Object) {
|
||
// nextTo is the last arg of obj; this is equivalent to a regular append
|
||
if nextTo.nextSiblingIndex == InvalidIndex {
|
||
tree.append(obj, arg)
|
||
return
|
||
}
|
||
|
||
arg.parentIndex = obj.index
|
||
arg.prevSiblingIndex = nextTo.index
|
||
arg.nextSiblingIndex = nextTo.nextSiblingIndex
|
||
|
||
tree.ObjectAt(arg.nextSiblingIndex).prevSiblingIndex = arg.index
|
||
nextTo.nextSiblingIndex = arg.index
|
||
}
|
||
|
||
// free appends obj to the tree's free object list allowing it to be re-used by
|
||
// future calls to NewObject and NewNamedObject. Callers must ensure that any
|
||
// held pointers to the object are not used after calling free.
|
||
func (tree *ObjectTree) free(obj *Object) {
|
||
if obj.parentIndex != InvalidIndex {
|
||
tree.detach(tree.ObjectAt(obj.parentIndex), obj)
|
||
}
|
||
|
||
if obj.firstArgIndex != InvalidIndex || obj.lastArgIndex != InvalidIndex {
|
||
panic("aml.ObjectTree: attempted to free object that still contains argument references")
|
||
}
|
||
|
||
// Push the object to the top of the free list and change its opcode to
|
||
// indicate this is a freed node
|
||
obj.opcode = pOpIntFreedObject
|
||
obj.nextSiblingIndex = tree.freeListHeadIndex
|
||
tree.freeListHeadIndex = obj.index
|
||
}
|
||
|
||
// detach detaches arg from obj's argument list.
|
||
func (tree *ObjectTree) detach(obj, arg *Object) {
|
||
if obj.firstArgIndex == arg.index {
|
||
obj.firstArgIndex = arg.nextSiblingIndex
|
||
}
|
||
|
||
if obj.lastArgIndex == arg.index {
|
||
obj.lastArgIndex = arg.prevSiblingIndex
|
||
}
|
||
|
||
if arg.nextSiblingIndex != InvalidIndex {
|
||
tree.ObjectAt(arg.nextSiblingIndex).prevSiblingIndex = arg.prevSiblingIndex
|
||
}
|
||
|
||
if arg.prevSiblingIndex != InvalidIndex {
|
||
tree.ObjectAt(arg.prevSiblingIndex).nextSiblingIndex = arg.nextSiblingIndex
|
||
}
|
||
|
||
arg.prevSiblingIndex = InvalidIndex
|
||
arg.nextSiblingIndex = InvalidIndex
|
||
arg.parentIndex = InvalidIndex
|
||
}
|
||
|
||
// ObjectAt returns a pointer to the Object at the specified index or nil if
|
||
// no object with this index exists inside the object tree.
|
||
func (tree *ObjectTree) ObjectAt(index uint32) *Object {
|
||
if index >= uint32(len(tree.objPool)) {
|
||
return nil
|
||
}
|
||
obj := tree.objPool[index]
|
||
if obj.opcode == pOpIntFreedObject {
|
||
return nil
|
||
}
|
||
|
||
return obj
|
||
}
|
||
|
||
// Find attempts to resolve the given expression into an Object using the rules
|
||
// specified in page 252 of the ACPI 6.2 spec:
|
||
//
|
||
// There are two types of namespace paths: an absolute namespace path (that is,
|
||
// one that starts with a ‘\’ prefix), and a relative namespace path (that is,
|
||
// one that is relative to the current namespace). The namespace search rules
|
||
// discussed above, only apply to single NameSeg paths, which is a relative
|
||
// namespace path. For those relative name paths that contain multiple NameSegs
|
||
// or Parent Prefixes, ‘^’, the search rules do not apply. If the search rules
|
||
// do not apply to a relative namespace path, the namespace object is looked up
|
||
// relative to the current namespace
|
||
func (tree *ObjectTree) Find(scopeIndex uint32, expr []byte) uint32 {
|
||
exprLen := len(expr)
|
||
if exprLen == 0 || scopeIndex == InvalidIndex {
|
||
return InvalidIndex
|
||
}
|
||
|
||
switch {
|
||
case expr[0] == '\\': // relative to the root scope
|
||
// Name was just `\`; this matches the root namespace
|
||
if exprLen == 1 {
|
||
return 0
|
||
}
|
||
|
||
return tree.findRelative(0, expr[1:])
|
||
case expr[0] == '^': // relative to the parent scope(s)
|
||
for startIndex := 0; startIndex < exprLen; startIndex++ {
|
||
switch expr[startIndex] {
|
||
case '^':
|
||
// Mpve up one parent. If we were at the root scope
|
||
// then the lookup failed.
|
||
if scopeIndex = tree.ObjectAt(scopeIndex).parentIndex; scopeIndex == InvalidIndex {
|
||
return InvalidIndex
|
||
}
|
||
default:
|
||
// Found the start of the name. Look it up relative to current scope
|
||
return tree.findRelative(scopeIndex, expr[startIndex:])
|
||
}
|
||
}
|
||
|
||
// Name was just a sequence of '^'; this matches the last scopeIndex value
|
||
return scopeIndex
|
||
case exprLen > amlNameLen:
|
||
// The expression consists of multiple name segments joined together (e.g. FOOFBAR0)
|
||
// In this case we need to apply relative lookup rules for FOOF.BAR0
|
||
return tree.findRelative(scopeIndex, expr)
|
||
case exprLen == amlNameLen:
|
||
// expr is a simple name. According to the spec, we need to
|
||
// search for it in this scope and all its parent scopes till
|
||
// we reach the root.
|
||
for nextScopeIndex := scopeIndex; nextScopeIndex != InvalidIndex; nextScopeIndex = tree.ObjectAt(nextScopeIndex).parentIndex {
|
||
scopeObj := tree.ObjectAt(nextScopeIndex)
|
||
checkNextSibling:
|
||
for nextIndex := scopeObj.firstArgIndex; nextIndex != InvalidIndex; nextIndex = tree.ObjectAt(nextIndex).nextSiblingIndex {
|
||
obj := tree.ObjectAt(nextIndex)
|
||
for byteIndex := 0; byteIndex < amlNameLen; byteIndex++ {
|
||
if expr[byteIndex] != obj.name[byteIndex] {
|
||
continue checkNextSibling
|
||
}
|
||
}
|
||
|
||
// Found match
|
||
return obj.index
|
||
}
|
||
}
|
||
}
|
||
|
||
// Not found
|
||
return InvalidIndex
|
||
}
|
||
|
||
// findRelative attempts to resolve an object using relative scope lookup rules.
|
||
func (tree *ObjectTree) findRelative(scopeIndex uint32, expr []byte) uint32 {
|
||
exprLen := len(expr)
|
||
|
||
nextSegment:
|
||
for segIndex := 0; segIndex < exprLen; segIndex += amlNameLen {
|
||
// If expr contains a dual or multinamed path then we may encounter special
|
||
// prefix chars in the stream (the parser extracts the raw data). In this
|
||
// case skip over them.
|
||
for ; segIndex < exprLen && expr[segIndex] != '_' && (expr[segIndex] < 'A' || expr[segIndex] > 'Z'); segIndex++ {
|
||
}
|
||
|
||
if exprLen-segIndex < amlNameLen {
|
||
return InvalidIndex
|
||
}
|
||
|
||
// Search current scope for an entity matching the next name segment
|
||
scopeObj := tree.ObjectAt(scopeIndex)
|
||
|
||
checkNextSibling:
|
||
for nextIndex := scopeObj.firstArgIndex; nextIndex != InvalidIndex; nextIndex = tree.ObjectAt(nextIndex).nextSiblingIndex {
|
||
obj := tree.ObjectAt(nextIndex)
|
||
for byteIndex := 0; byteIndex < amlNameLen; byteIndex++ {
|
||
if expr[segIndex+byteIndex] != obj.name[byteIndex] {
|
||
continue checkNextSibling
|
||
}
|
||
}
|
||
|
||
// Found match; set match as the next scope index and
|
||
// try to match the next segment
|
||
scopeIndex = nextIndex
|
||
continue nextSegment
|
||
}
|
||
|
||
// Failed to match next segment. Lookup failed
|
||
return InvalidIndex
|
||
}
|
||
|
||
// scopeIndex contains the index of the last matched name in the expression
|
||
// which is the target we were looking for.
|
||
return scopeIndex
|
||
}
|
||
|
||
// ClosestNamedAncestor returns the index of the first named object that is an
|
||
// ancestor of obj. If any of obj's parents are unresolved scope directives
|
||
// then the call will return InvalidIndex.
|
||
func (tree *ObjectTree) ClosestNamedAncestor(obj *Object) uint32 {
|
||
if obj == nil {
|
||
return InvalidIndex
|
||
}
|
||
|
||
for ancestorIndex := obj.parentIndex; ancestorIndex != InvalidIndex; {
|
||
ancestor := tree.ObjectAt(ancestorIndex)
|
||
if ancestor.opcode == pOpScope {
|
||
break
|
||
}
|
||
|
||
if pOpcodeTable[ancestor.infoIndex].flags&pOpFlagNamed != 0 {
|
||
return ancestorIndex
|
||
}
|
||
|
||
ancestorIndex = ancestor.parentIndex
|
||
}
|
||
|
||
return InvalidIndex
|
||
}
|
||
|
||
// NumArgs returns the number of arguments contained in obj.
|
||
func (tree *ObjectTree) NumArgs(obj *Object) uint32 {
|
||
if obj == nil {
|
||
return 0
|
||
}
|
||
|
||
var argCount uint32
|
||
for siblingIndex := obj.firstArgIndex; siblingIndex != InvalidIndex; siblingIndex = tree.ObjectAt(siblingIndex).nextSiblingIndex {
|
||
argCount++
|
||
}
|
||
|
||
return argCount
|
||
}
|
||
|
||
// ArgAt returns a pointer to obj's arg located at index.
|
||
func (tree *ObjectTree) ArgAt(obj *Object, index uint32) *Object {
|
||
if obj == nil {
|
||
return nil
|
||
}
|
||
for argIndex, siblingIndex := uint32(0), obj.firstArgIndex; siblingIndex != InvalidIndex; argIndex, siblingIndex = argIndex+1, tree.ObjectAt(siblingIndex).nextSiblingIndex {
|
||
if argIndex == index {
|
||
return tree.ObjectAt(siblingIndex)
|
||
}
|
||
}
|
||
|
||
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
|
||
}
|