1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

acpi: implement memory-based reader for AML byte-code streams

This commit is contained in:
Achilleas Anagnostopoulos 2017-08-28 09:28:00 +01:00
parent 4e985c91c6
commit 93125caa8a
2 changed files with 181 additions and 0 deletions

View File

@ -0,0 +1,84 @@
package aml
import (
"errors"
"io"
"reflect"
"unsafe"
)
var (
errInvalidUnreadByte = errors.New("amlStreamReader: invalid use of UnreadByte")
)
type amlStreamReader struct {
offset uint32
data []byte
}
// Init sets up the reader so it can read up to dataLen bytes from the virtual
// memory address dataAddr. If a non-zero initialOffset is specified, it will
// be used as the current offset in the stream.
func (r *amlStreamReader) Init(dataAddr uintptr, dataLen, initialOffset uint32) {
// Overlay a byte slice on top of the memory block to be accessed.
r.data = *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Len: int(dataLen),
Cap: int(dataLen),
Data: dataAddr,
}))
r.SetOffset(initialOffset)
}
// EOF returns true if the end of the stream has been reached.
func (r *amlStreamReader) EOF() bool {
return r.offset == uint32(len(r.data))
}
// ReadByte returns the next byte from the stream.
func (r *amlStreamReader) ReadByte() (byte, error) {
if r.EOF() {
return 0, io.EOF
}
r.offset++
return r.data[r.offset-1], nil
}
// PeekByte returns the next byte from the stream without advancing the read pointer.
func (r *amlStreamReader) PeekByte() (byte, error) {
if r.EOF() {
return 0, io.EOF
}
return r.data[r.offset], nil
}
// LastByte returns the last byte read off the stream
func (r *amlStreamReader) LastByte() (byte, error) {
if r.offset == 0 {
return 0, io.EOF
}
return r.data[r.offset-1], nil
}
// UnreadByte moves back the read pointer by one byte.
func (r *amlStreamReader) UnreadByte() error {
if r.offset == 0 {
return errInvalidUnreadByte
}
r.offset--
return nil
}
// Offset returns the current offset.
func (r *amlStreamReader) Offset() uint32 {
return r.offset
}
// SetOffset sets the reader offset to the supplied value.
func (r *amlStreamReader) SetOffset(off uint32) {
r.offset = off
}

View File

@ -0,0 +1,97 @@
package aml
import (
"io"
"testing"
"unsafe"
)
func TestAMLStreamReader(t *testing.T) {
buf := make([]byte, 16)
for i := 0; i < len(buf); i++ {
buf[i] = byte(i)
}
t.Run("without offset", func(t *testing.T) {
var r amlStreamReader
r.Init(
uintptr(unsafe.Pointer(&buf[0])),
uint32(len(buf)),
0,
)
if r.EOF() {
t.Fatal("unexpected EOF")
}
if err := r.UnreadByte(); err != errInvalidUnreadByte {
t.Fatalf("expected errInvalidUnreadByte; got %v", err)
}
if _, err := r.LastByte(); err != io.EOF {
t.Fatalf("unexpected error: %v", err)
}
for i := 0; i < len(buf); i++ {
exp := byte(i)
next, err := r.PeekByte()
if err != nil {
t.Fatal(err)
}
if next != exp {
t.Fatalf("expected PeekByte to return %d; got %d", exp, next)
}
next, err = r.ReadByte()
if err != nil {
t.Fatal(err)
}
if next != exp {
t.Fatalf("expected ReadByte to return %d; got %d", exp, next)
}
last, err := r.LastByte()
if err != nil {
t.Fatal(err)
}
if last != exp {
t.Fatalf("expected LastByte to return %d; got %d", exp, last)
}
}
if _, err := r.PeekByte(); err != io.EOF {
t.Fatalf("unexpected error: %v", err)
}
if _, err := r.ReadByte(); err != io.EOF {
t.Fatalf("unexpected error: %v", err)
}
exp := byte(len(buf) - 1)
if last, _ := r.LastByte(); last != exp {
t.Fatalf("expected LastByte to return %d; got %d", exp, last)
}
})
t.Run("with offset", func(t *testing.T) {
var r amlStreamReader
r.Init(
uintptr(unsafe.Pointer(&buf[0])),
uint32(len(buf)),
8,
)
if r.EOF() {
t.Fatal("unexpected EOF")
}
if exp, got := uint32(8), r.Offset(); got != exp {
t.Fatalf("expected Offset() to return %d; got %d", exp, got)
}
exp := byte(8)
if next, _ := r.ReadByte(); next != exp {
t.Fatalf("expected ReadByte to return %d; got %d", exp, next)
}
})
}