Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 64 additions & 5 deletions armdebug/conn_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/jon/ostiole/armdebug"
"github.com/jon/ostiole/coresight"
"github.com/jon/ostiole/dap"
"github.com/jon/ostiole/discover"
_ "github.com/jon/ostiole/discover/probes"
Expand Down Expand Up @@ -57,13 +58,41 @@ func TestHILArmConnection(t *testing.T) {
t.Fatal(err)
}
t.Logf("provider=%s probe=%+v DPIDR=%#08x requested_clock_hz=100000", selection.Provider, c.Info(), id)
if id>>12&15 == 3 {
for _, reg := range []dap.DPRegister{dap.DPIDR1, dap.BASEPTR0, dap.BASEPTR1, dap.DPIDR} {
value, err := c.Port().ReadDP(ctx, reg)
if err != nil {
t.Fatal(err)
}
t.Logf("%s=%#08x", reg, value)
}

}

if os.Getenv("OSTIOLE_ARMDEBUG_HIL_DEBUG_SPACE") == "1" {
inspectDebugSpaceHIL(t, ctx, c.Port().DebugSpace())
}
if inspectMemory {
inspectMemoryHIL(t, ctx, c, ap)
}
}

func memorySelectionHIL(t *testing.T) (dap.APSel, bool) {
t.Helper()
if selected := os.Getenv("OSTIOLE_ARMDEBUG_HIL_AP_BASE"); selected != "" {
if os.Getenv("OSTIOLE_ARMDEBUG_HIL_AP") != "" {
t.Fatal("select either an AP index or base")
}
base, err := strconv.ParseUint(selected, 0, 64)
if err != nil {
t.Fatal(err)
}
sel, err := dap.APAt(base)
if err != nil {
t.Fatal(err)
}
return sel, true
}
selected := os.Getenv("OSTIOLE_ARMDEBUG_HIL_AP")
if selected == "" {
return dap.APSel{}, false
Expand All @@ -77,10 +106,6 @@ func memorySelectionHIL(t *testing.T) (dap.APSel, bool) {

func inspectMemoryHIL(t *testing.T, ctx context.Context, c *armdebug.Conn, ap dap.APSel) {
t.Helper()
index, err := ap.Value()
if err != nil {
t.Fatal(err)
}
id, err := c.Port().ReadAPIDR(ctx, ap)
if err != nil {
t.Fatal(err)
Expand All @@ -93,7 +118,20 @@ func inspectMemoryHIL(t *testing.T, ctx context.Context, c *armdebug.Conn, ap da
if err != nil {
t.Fatal(err)
}
t.Logf("AP%d IDR=%#08x CPUID=%#08x", index, id.Raw, processor.Raw)
base, present, err := memory.ReadDebugBase(ctx)
if err != nil {
t.Fatal(err)
}
t.Logf("%s IDR=%#08x CPUID=%#08x debug_base=%#x present=%v", ap, id.Raw, processor.Raw, base, present)
if present && os.Getenv("OSTIOLE_ARMDEBUG_HIL_WALK") == "1" {
visits, err := coresight.Walk(ctx, memory, base, coresight.WalkLimits{MaxDepth: 8, MaxComponents: 64, MaxEntries: 256})
for _, visit := range visits {
t.Logf("ROM component=%+v error=%v", visit.Component, visit.Err)
}
if err != nil {
t.Fatal(err)
}
}
}

func closeHIL(t *testing.T, c *armdebug.Conn) {
Expand All @@ -107,3 +145,24 @@ func closeHIL(t *testing.T, c *armdebug.Conn) {
}
t.Errorf("cleanup remains pending after three attempts: %v", err)
}

func inspectDebugSpaceHIL(t *testing.T, ctx context.Context, space dap.DebugSpace) {
t.Helper()
base, present, err := space.ReadDebugBase(ctx)
if err != nil || !present {
t.Fatalf("debug root=%#x,%v,%v", base, present, err)
}
visits, err := coresight.Walk(ctx, space, base, coresight.WalkLimits{MaxDepth: 8, MaxComponents: 64, MaxEntries: 256})
for _, visit := range visits {
if visit.Component != nil {
t.Logf("debug-space base=%#x CIDR=%#08x PIDR=%#x DEVARCH=%#08x", visit.Component.Base, visit.Component.CIDR, visit.Component.PIDR, visit.Component.DEVARCH)
}
if visit.Err != nil {
t.Log(visit.Err)
}
}
t.Logf("debug-space visits=%d complete=%v", len(visits), err == nil)
if err != nil {
t.Fatal(err)
}
}
7 changes: 1 addition & 6 deletions armdebug/memap.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package armdebug
import (
"context"
"errors"
"fmt"

"github.com/jon/ostiole/dap"
)
Expand All @@ -28,13 +27,9 @@ func (c *Conn) OpenMemAP(ctx context.Context, ap dap.APSel) (*dap.MemAP, error)
if err := ctx.Err(); err != nil {
return nil, err
}
index, err := ap.Value()
if err != nil {
return nil, err
}
for _, owned := range c.memories {
if owned.selection == ap {
return nil, fmt.Errorf("armdebug: AP %d is already owned", index)
return nil, errors.New("armdebug: access port is already owned")
}
}
client, err := dap.OpenMemAP(ctx, c.port, ap)
Expand Down
45 changes: 45 additions & 0 deletions armdebug/memap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/jon/ostiole/armdebug"
"github.com/jon/ostiole/dap"
dapsim "github.com/jon/ostiole/dap/sim"
"github.com/jon/ostiole/probe"
swdsim "github.com/jon/ostiole/swd/sim"
)
Expand Down Expand Up @@ -124,3 +125,47 @@ func TestMemAPCleanupFailureKeepsProbe(t *testing.T) {
t.Fatalf("cleanup retry: %v", err)
}
}

func TestOwnedAPv2Memory(t *testing.T) {
b := newBench()
b.target.Target = dapsim.New(0x4c013477)
if err := b.target.SetDPRegister(dap.DPIDR1, 20); err != nil {
t.Fatal(err)
}
sel, err := dap.APAt(0x2000)
if err != nil {
t.Fatal(err)
}
if err := b.target.AddMEMAP(sel, 0x34770008, map[uint32]uint32{0x100: 7}); err != nil {
t.Fatal(err)
}
c, err := armdebug.Connect(t.Context(), probe.New(probe.Info{}, b), config())
if err != nil {
t.Fatal(err)
}
mem, err := c.OpenMemAP(t.Context(), sel)
if err != nil {
t.Fatal(err)
}
if got, err := mem.ReadWord(t.Context(), 0x100); err != nil || got != 7 {
t.Fatalf("read=%#x,%v", got, err)
}
before := b.transfers
if _, err := c.OpenMemAP(t.Context(), sel); err == nil || b.transfers != before {
t.Fatal("duplicate AP reached hardware")
}
failure := errors.New("restore failed")
b.target.beforeWrite = func(req swdsim.Request, selected, value uint32) error {
if req.AP && req.Addr == 4 && selected&^15 == 0x2d00 {
return failure
}
return nil
}
if err := c.Close(); !errors.Is(err, failure) || b.closes != 0 {
t.Fatalf("close=%v, probe closes=%d", err, b.closes)
}
b.target.beforeWrite = nil
if err := c.Close(); err != nil || b.closes != 1 {
t.Fatalf("retry=%v, probe closes=%d", err, b.closes)
}
}
2 changes: 1 addition & 1 deletion cmsisdap/session_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func observeCMSISDAPTarget(t *testing.T, ctx context.Context, readyOnOpen bool)

func assertCMSISDAPAPRegister(t *testing.T, ctx context.Context, debugPort *dap.DebugPort, address uint8, want uint32) {
t.Helper()
got, err := debugPort.ReadRawAP(ctx, dap.NewAPSel(0).Address(address))
got, err := debugPort.ReadRawAP(ctx, dap.NewAPSel(0).Address(uint16(address)))
if err != nil {
t.Fatal(err)
}
Expand Down
57 changes: 57 additions & 0 deletions coresight/debugspace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package coresight_test

import (
"errors"
"testing"

"github.com/jon/ostiole/coresight"
"github.com/jon/ostiole/dap"
"github.com/jon/ostiole/dap/sim"
"github.com/jon/ostiole/swd"
swdsim "github.com/jon/ostiole/swd/sim"
)

func TestWalkThroughDebugSpace(t *testing.T) {
target := sim.New(0x4c013477)
for reg, value := range map[dap.DPRegister]uint32{dap.DPIDR1: 20, dap.BASEPTR0: 1} {
if err := target.SetDPRegister(reg, value); err != nil {
t.Fatal(err)
}
}
root := memoryAt(0, 1)
root.words[0] = 0x2003
root.words[4] = 0
child := memoryAt(0x2000, 9)
child.words[0x2fbc] = 0x47700a17
for _, memory := range []*componentMemory{root, child} {
for address, value := range memory.words {
if err := target.SetDebugWord(address, value); err != nil {
t.Fatal(err)
}
}
}
dp := dap.NewDebugPort(dap.SWDP(swd.New(swdsim.New(target))))
if _, err := dp.Connect(t.Context()); err != nil {
t.Fatal(err)
}
t.Cleanup(func() { releaseSimulation(t, dp.Release) })
space := dp.DebugSpace()
base, present, err := space.ReadDebugBase(t.Context())
if err != nil || !present || base != 0 {
t.Fatalf("root=%#x,%v,%v", base, present, err)
}
visits, err := coresight.Walk(t.Context(), space, base, walkLimits())
if err != nil || len(visits) != 2 {
t.Fatalf("walk=%+v,%v", visits, err)
}
arch, ok := visits[1].Component.Architecture()
if !ok || arch.ID != 0x0a17 || visits[1].Component.Base != 0x2000 {
t.Fatalf("AP=%+v", visits[1])
}
limits := walkLimits()
limits.MaxComponents = 1
visits, err = coresight.Walk(t.Context(), space, base, limits)
if !errors.Is(err, coresight.ErrWalkLimit) || len(visits) != 1 {
t.Fatalf("bounded walk=%+v,%v", visits, err)
}
}
67 changes: 67 additions & 0 deletions dap/adiv6_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package dap_test

import (
"testing"

"github.com/jon/ostiole/dap"
dapsim "github.com/jon/ostiole/dap/sim"
"github.com/jon/ostiole/swd"
swdsim "github.com/jon/ostiole/swd/sim"
)

func TestDPv3BankedIdentity(t *testing.T) {
target := dapsim.New(0x4c013477)
for reg, value := range map[dap.DPRegister]uint32{dap.DPIDR1: 32, dap.BASEPTR0: 0x1001, dap.BASEPTR1: 0, dap.DLCR: 0} {
if err := target.SetDPRegister(reg, value); err != nil {
t.Fatal(err)
}
}
dp := dap.NewDebugPort(dap.SWDP(swd.New(swdsim.New(target))))
if _, err := dp.Connect(t.Context()); err != nil {
t.Fatal(err)
}
defer func() {
if err := dp.Release(t.Context()); err != nil {
t.Error(err)
}
}()
for _, reg := range []dap.DPRegister{dap.DPIDR1, dap.BASEPTR0, dap.BASEPTR1, dap.DPIDR} {
got, err := dp.ReadDP(t.Context(), reg)
want := map[dap.DPRegister]uint32{dap.DPIDR1: 32, dap.BASEPTR0: 0x1001, dap.BASEPTR1: 0, dap.DPIDR: 0x4c013477}[reg]
if err != nil || got != want {
t.Fatalf("%s = %#x, %v; want %#x", reg, got, err, want)
}
}
txn := dp.NewTxn()
base := txn.ReadDP(dap.BASEPTR0)
id := txn.ReadDP(dap.DPIDR)
if err := txn.Commit(t.Context()); err != nil {
t.Fatal(err)
}
if got, err := base.Value(); err != nil || got != 0x1001 {
t.Fatalf("base = %#x, %v", got, err)
}
if got, err := id.Value(); err != nil || got != 0x4c013477 {
t.Fatalf("identity = %#x, %v", got, err)
}
}

func TestADIv6RegistersRejectADIv5(t *testing.T) {
target := newWaitTarget()
dp := newDebugPort(t, target)
if _, err := dp.Connect(t.Context()); err != nil {
t.Fatal(err)
}
before := len(target.requests)
for _, reg := range []dap.DPRegister{dap.DPIDR1, dap.BASEPTR0, dap.BASEPTR1, dap.SELECT1} {
if _, err := dp.ReadDP(t.Context(), reg); err == nil {
t.Fatalf("read %s accepted", reg)
}
if err := dp.WriteDP(t.Context(), reg, 0); err == nil {
t.Fatalf("write %s accepted", reg)
}
}
if len(target.requests) != before {
t.Fatal("invalid registers sent traffic")
}
}
Loading
Loading