mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
acpi: implement reader abstraction for AML in-memory byte-streams
This commit is contained in:
parent
b00fff0e39
commit
98fe98bc83
106
src/gopheros/device/acpi/aml/stream_reader.go
Normal file
106
src/gopheros/device/acpi/aml/stream_reader.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package aml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopheros/kernel"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errInvalidUnreadByte = &kernel.Error{Module: "acpi_aml_parser", Message: "bad call to UnreadByte; stream offset is 0"}
|
||||||
|
errInvalidPkgEnd = &kernel.Error{Module: "acpi_aml_parser", Message: "attempted to set pkgEnd past the end of the stream"}
|
||||||
|
errReadPastPkgEnd = &kernel.Error{Module: "acpi_aml_parser", Message: "attempted to read past pkgEnd"}
|
||||||
|
)
|
||||||
|
|
||||||
|
type amlStreamReader struct {
|
||||||
|
offset uint32
|
||||||
|
data []byte
|
||||||
|
pkgEnd uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 pkg has been reached.
|
||||||
|
func (r *amlStreamReader) EOF() bool {
|
||||||
|
return r.offset == r.pkgEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *amlStreamReader) SetPkgEnd(pkgEnd uint32) error {
|
||||||
|
if pkgEnd > uint32(len(r.data)) {
|
||||||
|
return errInvalidPkgEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
r.pkgEnd = pkgEnd
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadByte returns the next byte from the stream.
|
||||||
|
func (r *amlStreamReader) ReadByte() (byte, error) {
|
||||||
|
if r.EOF() {
|
||||||
|
return 0, errReadPastPkgEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
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, errReadPastPkgEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
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, errReadPastPkgEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataPtr returns a pointer to the stream contents at the current stream offset.
|
||||||
|
func (r *amlStreamReader) DataPtr() uintptr {
|
||||||
|
if r.EOF() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return uintptr(unsafe.Pointer(&r.data[r.offset]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOffset sets the reader offset to the supplied value.
|
||||||
|
func (r *amlStreamReader) SetOffset(off uint32) {
|
||||||
|
if max := uint32(len(r.data)); off > max {
|
||||||
|
off = max
|
||||||
|
}
|
||||||
|
r.offset = off
|
||||||
|
}
|
131
src/gopheros/device/acpi/aml/stream_reader_test.go
Normal file
131
src/gopheros/device/acpi/aml/stream_reader_test.go
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
package aml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"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 err := r.SetPkgEnd(uint32(len(buf) + 1)); err != errInvalidPkgEnd {
|
||||||
|
t.Fatalf("expected to get errInvalidPkgEnd; got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.SetPkgEnd(uint32(len(buf))); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 != errReadPastPkgEnd {
|
||||||
|
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.UnreadByte(); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set offset past EOF; reader should cap the offset to len(buf)
|
||||||
|
r.SetOffset(math.MaxUint32)
|
||||||
|
|
||||||
|
if _, err := r.PeekByte(); err != errReadPastPkgEnd {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := r.ReadByte(); err != errReadPastPkgEnd {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ptr to data", 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.SetOffset(2)
|
||||||
|
ptr := r.DataPtr()
|
||||||
|
if got := *((*byte)(unsafe.Pointer(ptr))); got != buf[2] {
|
||||||
|
t.Fatal("expected DataPtr to return a pointer to buf[2]")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user