ms-tools/cli/memio.go
2022-11-20 18:19:34 +01:00

188 lines
4.1 KiB
Go

package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io/ioutil"
"time"
"github.com/BertoldVdb/ms-tools/mshal"
"github.com/inancgumus/screen"
)
type MEMIOListRegions struct {
}
func (l *MEMIOListRegions) Run(c *Context) error {
var regions []mshal.MemoryRegion
for _, m := range c.hal.MemoryRegionList() {
regions = append(regions, c.hal.MemoryRegionGet(m))
}
fmt.Printf("Region | Length | Parent (%s)\n", c.hal.GetDeviceType())
for _, m := range regions {
parent, offset := mshal.RecursiveGetParentAddress(m, 0)
fmt.Printf("%-13s| %5d |", m.GetName(), m.GetLength())
if parent != m {
fmt.Printf(" %s.%04X", parent.GetName(), offset)
}
fmt.Printf("\n")
}
return nil
}
type Region struct {
Region string `arg name:"region" help:"Memory region to access."`
Addr int `arg name:"addr" help:"Addresses to access." type:"int"`
}
type MEMIOReadCmd struct {
Loop int `optional help:"0=Perform once, 1=Mark changes since start, 2=Mark changes since previous iteration."`
Filename string `optional help:"File to write dump to."`
Region Region `embed`
Amount int `arg name:"amount" help:"Number of bytes to read, omit for maximum." optional default:"0"`
}
func (l *MEMIOReadCmd) Run(c *Context) error {
if l.Loop < 0 || l.Loop > 2 {
return errors.New("Loop flag out of range")
}
region := c.hal.MemoryRegionGet(mshal.MemoryRegionNameType(l.Region.Region))
if region == nil {
return errors.New("Invalid memory region")
}
if l.Amount == 0 {
l.Amount = region.GetLength()
}
var oldBuf []byte
var mark []bool
for {
startTime := time.Now()
if l.Loop == 2 || mark == nil {
mark = make([]bool, l.Amount)
}
buf := make([]byte, l.Amount)
n, err := region.Access(false, l.Region.Addr, buf)
if err != nil {
return fmt.Errorf("Read error: %s", err.Error())
}
buf = buf[:n]
if l.Filename != "" {
err := ioutil.WriteFile(l.Filename, buf, 0644)
return err
}
if l.Amount == 1 {
if len(buf) < 1 {
return errors.New("0 bytes returned")
}
fmt.Printf("0x%02x\n", buf[0])
} else {
if l.Loop != 0 {
screen.Clear()
screen.MoveTopLeft()
if oldBuf != nil {
for i, m := range oldBuf {
if m != buf[i] {
mark[i] = true
}
}
}
}
fmt.Println(hexdump(l.Region.Addr, buf, mark))
}
oldBuf = buf
if l.Loop == 0 {
break
}
d := time.Now().Sub(startTime)
td := 200 * time.Millisecond
if d < td {
time.Sleep(td - d)
}
}
return nil
}
type MEMIOWriteCmd struct {
Zone Region `embed`
Value int `arg name:"value" help:"Value to write." type:"int"`
}
func (w MEMIOWriteCmd) Run(c *Context) error {
region := c.hal.MemoryRegionGet(mshal.MemoryRegionNameType(w.Zone.Region))
if region == nil {
return errors.New("Invalid memory region")
}
if region.GetAlignment() == 4 {
var value [4]byte
binary.BigEndian.PutUint32(value[:], uint32(w.Value))
_, err := region.Access(true, w.Zone.Addr, value[:])
return err
}
if region.GetAlignment() == 2 {
var value [2]byte
binary.BigEndian.PutUint16(value[:], uint16(w.Value))
_, err := region.Access(true, w.Zone.Addr, value[:])
return err
}
var value [1]byte
value[0] = byte(w.Value)
_, err := region.Access(true, w.Zone.Addr, value[:])
return err
}
type MEMIOWriteFileCmd struct {
Region Region `embed`
Filename string `arg name:"filename" help:"File to read data from."`
Verify bool `optional name:"verify" help:"Read and verify written file."`
}
func (w MEMIOWriteFileCmd) Run(c *Context) error {
data, err := ioutil.ReadFile(w.Filename)
if err != nil {
return err
}
region := c.hal.MemoryRegionGet(mshal.MemoryRegionNameType(w.Region.Region))
if region == nil {
return errors.New("Invalid memory region")
}
n, err := region.Access(true, w.Region.Addr, data)
if n > 0 {
fmt.Printf("Wrote %d bytes to %s:%04x.\n", n, w.Region.Region, w.Region.Addr)
}
if w.Verify {
readback := make([]byte, len(data))
_, err := region.Access(false, w.Region.Addr, readback)
if err != nil {
return err
}
if !bytes.Equal(readback, data) {
return errors.New("Failed to verify write")
}
fmt.Println("Verification OK.")
}
return err
}