Last active
August 29, 2015 13:57
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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