Skip to content

Instantly share code, notes, and snippets.

@distributed
Last active August 29, 2015 13:57
Show Gist options
  • Save distributed/9357128 to your computer and use it in GitHub Desktop.
Save distributed/9357128 to your computer and use it in GitHub Desktop.
reads memory from a coldfire processor connected via usb tap. communication is done with the codewarrior connection server over TCP.
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"github.com/davecgh/go-spew/spew"
"io"
"log"
"net"
"time"
)
// make CCS verbose by typing "log verbose"
func main() {
err := func() error {
conn, err := net.Dial("tcp4", "localhost:41475")
if err != nil {
return err
}
/*err = initfiddle(conn)
if err != nil {
return err
}*/
err = newInit(conn)
if err != nil {
return err
}
return nil
}()
if err != nil {
log.Fatal(err)
}
}
const coreColdfire = 25
func newInit(conn net.Conn) error {
c, err := NewConnection(conn)
if err != nil {
return err
}
err = c.checkMinVersion()
if err != nil {
return err
}
fmt.Printf("api version is OK\n")
nconn, err := c.getConnectionCount()
if err != nil {
return err
}
fmt.Printf("number of open CCS connetions: %d\n", nconn)
availableConnections(c.conn)
//err = c.setupCC("utap_bdm:10371012")
err = c.setupCC("utap_bdm:0")
if err != nil {
return err
}
// TODO: is it really cc 0?
defer c.deleteCC(0)
availableConnections(c.conn)
err = c.configDriver(0, []byte{0, 0, 0, 1})
if err != nil {
return err
}
err = c.configChain(0, coreColdfire)
if err != nil {
return err
}
// cc_index 0, chain_pos 0, khz 22222
err = c.setMaxTck(0, 0, 22222)
fmt.Printf("chain configured\n")
// readMem(cc, chainpos, space, size, addr, count uint32) error {
tsiz := 1024 * 1024
bsiz := 64 * 1024
nleft := tsiz
ldsiz := uint32(4)
fmt.Printf("fetching tsiz %5.1f kbytes, bsiz %5.1f kbytes, ldsiz %d bytes\n", float64(tsiz)/1024.0, float64(bsiz)/1024.0, ldsiz)
buf := bytes.NewBuffer(nil)
tstart := time.Now()
for nleft > 0 {
siz := bsiz
if nleft < siz {
siz = nleft
}
offs := tsiz - nleft
addr := 0x46000000 + uint32(offs)
//fmt.Printf("fetching at %#08x, size %#04x ... ", addr, uint32(siz))
d, err := c.readMem(0, 0, 0, ldsiz, addr, uint32(siz))
if err != nil {
return err
}
_ = d
//fmt.Printf("OK, %#x bytes\n", len(d))
buf.Write(d)
nleft -= siz
}
tend := time.Now()
rate := float64(tsiz) / tend.Sub(tstart).Seconds()
fmt.Printf("transfer speed: %5.1f kbytes/s\n", rate/1024.0)
/*err = ioutil.WriteFile("e:\\memdump1m.versans", buf.Bytes(), 0666)
if err != nil {
return err
}*/
return nil
}
func initprint(conn io.ReadWriter) error {
_, err := conn.Write(initmsg)
if err != nil {
return err
}
ans, err := readFrame(conn)
if err != nil {
return err
}
spew.Dump(ans)
return nil
}
func (c *Connection) checkMinVersion() error {
_, err := c.ExecuteWireCommand(
"check_min_version",
WireCommand{
cmdHeader{Command: 0x25},
[]byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06},
})
return err
}
func (c *Connection) setupCC(name string) error {
cmd := WireCommand{
cmdHeader{
Command: 0,
},
[]byte(name + "\x00"),
}
res, err := c.ExecuteWireCommand("setup_cc", cmd)
if err != nil {
return err
}
fmt.Printf("setup_cc OK:\n%s\n", res.String())
return nil
}
func (c *Connection) getConnectionCount() (n uint32, err error) {
cmd := WireCommand{
cmdHeader{Command: 0x33},
nil,
}
var res WireResult
res, err = c.ExecuteWireCommand("get_connection_count", cmd)
if err != nil {
return
}
// TODO: why is the first result at index 4?
n = res.Results[4]
return
}
func (c *Connection) configDriver(configReg uint32, configData []byte) error {
cmd := WireCommand{
cmdHeader{Command: 0x4b},
configData,
}
cmd.Args[0] = configReg
_, err := c.ExecuteWireCommand("config_driver", cmd)
if err != nil {
return err
}
return nil
}
func (c *Connection) configChain(cc uint32, core uint32) error {
// ex: config_chain(serverh=0,cc=0,count=1,*devlist,*generic)
// devlist: coldfire
//
// TODO: what is count? num entries in devlist? core is
// an mkcore core number, 25 or 0x19 for coldfire
// what is generic?
//
corelist := make([]byte, 4)
putUint32(corelist, core)
cmd := WireCommand{
cmdHeader{Command: 0x05},
corelist,
}
cmd.Args[1] = cc
cmd.Args[6] = 1 // count
_, err := c.ExecuteWireCommand("config_chain", cmd)
if err != nil {
return err
}
return nil
}
func (c *Connection) deleteCC(cc uint32) error {
cmd := WireCommand{
cmdHeader{Command: 0x01},
nil,
}
cmd.Args[8] = cc
_, err := c.ExecuteWireCommand("delete_cc", cmd)
if err != nil {
return err
}
return nil
}
func (c *Connection) setMaxTck(cc uint32, chainPos uint32, khz uint32) error {
cmd := WireCommand{
cmdHeader{Command: 0x06},
nil,
}
cmd.Args[1] = cc
cmd.Args[2] = chainPos
cmd.Args[6] = khz
_, err := c.ExecuteWireCommand("set_max_tck", cmd)
if err != nil {
return err
}
return nil
}
func (c *Connection) readMem(cc, chainpos, space, size, addr, count uint32) ([]byte, error) {
cmd := WireCommand{
cmdHeader{Command: 0x0d},
nil,
}
cmd.Args[0] = 0 // serverh
cmd.Args[1] = cc
cmd.Args[2] = chainpos
cmd.Args[3] = space
cmd.Args[4] = size
cmd.Args[5] = addr
cmd.Args[6] = count
res, err := c.ExecuteWireCommand("read_mem", cmd)
if err != nil {
return nil, err
}
// TODO: verification of size, count
//fmt.Println(res)
return res.Trailer, nil
}
func availableConnections(conn io.ReadWriter) error {
hdr := cmdHeader{
Len: 0x30,
Command: 0x04,
SeqNr: 0x5abd,
}
trailer := []byte{}
err := binary.Write(conn, binary.BigEndian, hdr)
if err != nil {
return err
}
_, err = conn.Write(trailer)
if err != nil {
return err
}
ans, err := readFrame(conn)
if err != nil {
return err
}
// TODO: list of available connections
// seems to be in little endian:
// {0, 71, <provided ID of setup_cc>}
// in the case of non-present usbtap serial
// numbers, the id provided by setup_cc seems
// to be interpreted in decimal. in the case of
// a present usb tap, the id seems to be
// interpreted as a hex string. qecqln?
//spew.Dump("available connections", ans)
_ = ans
return nil
}
func initfiddle(conn io.ReadWriter) error {
/*err := checkApiVersion(conn)
if err != nil {
return err
}
err = getConnectionCount(conn)
if err != nil {
return err
}
err = availableConnections(conn)
if err != nil {
return err
}
// only works if conn was not available already
// the :0 is some sort of identifier for an opened
// cc.
err = setupCC(conn, "utap_bdm:0")
if err != nil {
return err
}
*/
return nil
}
func readFrame(r io.Reader) ([]byte, error) {
var scratch [4]byte
_, err := io.ReadFull(r, scratch[:])
if err != nil {
return nil, err
}
siz, _ := getUint32(scratch[:])
if siz < 4 {
return nil, errors.New("frame size too small")
}
buf := make([]byte, siz)
_, err = io.ReadFull(r, buf[4:])
if err != nil {
return nil, err
}
copy(buf[0:4], scratch[:])
return buf, nil
}
var initmsg = []byte{
0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0xcc, 0x40, 0x52, 0xf3, 0xc0,
0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x40, 0x77, 0xb3, 0x4d, 0x00, 0x00, 0x3c, 0xc6,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06}
func getUint32(b []byte) (uint32, []byte) {
v := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
return v, b[4:]
}
func putUint32(b []byte, v uint32) []byte {
b[0] = uint8(v >> 24)
b[1] = uint8(v >> 16)
b[2] = uint8(v >> 8)
b[3] = uint8(v >> 0)
return b[4:]
}
const cmdHeaderSize = 0x30
type cmdHeader struct {
Len uint32
Command uint32
Args [36 / 4]uint32
SeqNr uint32
}
type WireCommand struct {
cmdHeader
Trailer []byte
}
const resHeaderSize = 0x28
// the user does not have to provide a correct length field
// since it is fixed up by the networking code
type resHeader struct {
Len uint32
Command uint32
Results [7]uint32
SeqNr uint32
}
type WireResult struct {
resHeader
Trailer []byte
}
func (w WireResult) String() string {
s := fmt.Sprintf("res len %#04x cmd %04x", w.Len, w.Command)
for i, arg := range w.Results {
s += fmt.Sprintf(" arg%d %08x", i, arg)
if i == 3 {
s += "\n "
}
}
if len(w.Trailer) == 0 {
s += " trailer{}"
} else {
s += " trailer:\n" + spew.Sdump(w.Trailer)
}
return s
}
func (w WireResult) CommandError() error {
res := w.Results[0]
if res != 0 {
return fmt.Errorf("ccs error %d, %#x", res, res)
}
return nil
}
type Connection struct {
conn net.Conn
connerr error
scratch [4]byte
}
func NewConnection(conn net.Conn) (*Connection, error) {
return &Connection{
conn: conn,
}, nil
}
func (c *Connection) stickyError() error {
return c.connerr
}
func (c *Connection) updateStickyError(err error) {
if c.connerr == nil && err != nil {
c.connerr = err
}
}
func (c *Connection) ExchangeWireCommand(cmd WireCommand) (res WireResult, err error) {
err = c.stickyError()
if err != nil {
return
}
err = c.writeWireCommand(cmd)
if err != nil {
return
}
res, err = c.readWireResult()
if err != nil {
return
}
return
}
// TODO: deduce name from command number
func (c *Connection) ExecuteWireCommand(name string, cmd WireCommand) (res WireResult, err error) {
res, err = c.ExchangeWireCommand(cmd)
if err != nil {
err = OpError{name, err}
return
}
err = res.CommandError()
if err != nil {
err = OpError{name, err}
return
}
return
}
func (c *Connection) readFrame() ([]byte, error) {
_, err := io.ReadFull(c.conn, c.scratch[:4])
if err != nil {
c.updateStickyError(err)
return nil, err
}
siz, _ := getUint32(c.scratch[:4])
if siz < 4 {
c.updateStickyError(err)
return nil, errors.New("frame size too small")
}
buf := make([]byte, siz)
_, err = io.ReadFull(c.conn, buf[4:])
if err != nil {
c.updateStickyError(err)
return nil, err
}
copy(buf[0:4], c.scratch[:4])
return buf, nil
}
func (c *Connection) readWireResult() (res WireResult, err error) {
var frame []byte
frame, err = c.readFrame()
if err != nil {
return
}
r := bytes.NewReader(frame)
err = binary.Read(r, binary.BigEndian, &res.resHeader)
if err != nil {
return
}
res.Trailer = frame[resHeaderSize:]
return
}
func (c *Connection) writeWireCommand(cmd WireCommand) (err error) {
framelen := cmdHeaderSize + len(cmd.Trailer)
w := bytes.NewBuffer(nil)
w.Grow(framelen)
cmd.cmdHeader.Len = uint32(framelen) // fix up frame len
err = binary.Write(w, binary.BigEndian, cmd.cmdHeader)
if err != nil {
return err
}
// *bytes.Buffer.Write wil not fail
w.Write(cmd.Trailer)
_, err = c.conn.Write(w.Bytes())
if err != nil {
c.updateStickyError(err)
return
}
return
}
type OpError struct {
Op string
Err error
}
func (oe OpError) Error() string {
return "error on " + oe.Op + ": " + oe.Err.Error()
}
func stringOpError(op, s string) OpError {
return OpError{op, errors.New(s)}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment