Add line-ending policy to .gitattributes; renormalize

* text=auto eol=lf (store LF, check out LF) with *.ps1 text eol=crlf so the
Windows PowerShell scripts stay CRLF. Prevents the CRLF<->LF churn that made the
whole-file diffs. The .ps1 working-tree bytes are unchanged.
This commit is contained in:
Kevin Thomas committed 2026-10-04 11:00:37 -04:00
1 parent 16ece6a119
commit 9d739f816e
3 files changed
+417 -411

No files matched your search

+6
View File
@@ -4,3 +4,9 @@
*.txt linguist-detectable=false *.txt linguist-detectable=false
*.json linguist-detectable=false *.json linguist-detectable=false
*.ps1 linguist-detectable=false *.ps1 linguist-detectable=false
# Line endings: store LF in the repository; check out LF everywhere except the
# Windows PowerShell scripts, which stay CRLF. Prevents CRLF<->LF churn.
* text=auto eol=lf
*.ps1 text eol=crlf
+279 -279
View File
@@ -1,279 +1,279 @@
<# <#
.SYNOPSIS .SYNOPSIS
Start OpenOCD as a live GDB server for the RP2350 via the Pico Debug Probe. Start OpenOCD as a live GDB server for the RP2350 via the Pico Debug Probe.
.DESCRIPTION .DESCRIPTION
Starts OpenOCD in the foreground as a long-running GDB server. It exposes Starts OpenOCD in the foreground as a long-running GDB server. It exposes
rp2350.dap.core0 on 127.0.0.1:3333 and leaves the core RUNNING, so that a rp2350.dap.core0 on 127.0.0.1:3333 and leaves the core RUNNING, so that a
debugger (Binary Ninja, or plain GDB) can attach to a target that is already debugger (Binary Ninja, or plain GDB) can attach to a target that is already
executing and therefore has sane registers. executing and therefore has sane registers.
This script is deliberately NOT flash.ps1. flash.ps1 programs flash and This script is deliberately NOT flash.ps1. flash.ps1 programs flash and
exits; this one claims the probe and stays up so you can single-step, read exits; this one claims the probe and stays up so you can single-step, read
memory, and set breakpoints. Do not run both at once -- exactly one process memory, and set breakpoints. Do not run both at once -- exactly one process
may own the debug probe. may own the debug probe.
The script ends with "reset run" rather than OpenOCD's default halt. This is The script ends with "reset run" rather than OpenOCD's default halt. This is
the single most important line in the file; see "Why reset run" below. the single most important line in the file; see "Why reset run" below.
.PARAMETER OCD .PARAMETER OCD
Optional. Directory containing openocd.exe AND its scripts\ directory. Optional. Directory containing openocd.exe AND its scripts\ directory.
Overrides the PICO_OPENOCD environment variable. Overrides the PICO_OPENOCD environment variable.
.ENVIRONMENT .ENVIRONMENT
PICO_OPENOCD Directory containing openocd.exe AND its scripts\ directory. PICO_OPENOCD Directory containing openocd.exe AND its scripts\ directory.
Default: $env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev Default: $env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev
The path is used for BOTH the executable and the -s scripts The path is used for BOTH the executable and the -s scripts
argument. This must be an OpenOCD build matching your machine argument. This must be an OpenOCD build matching your machine
architecture (x64). architecture (x64).
ADAPTER_SPEED SWD clock in kHz. Default: 24000. ADAPTER_SPEED SWD clock in kHz. Default: 24000.
This is a read-mostly debug session, so a fast clock is fine This is a read-mostly debug session, so a fast clock is fine
and makes stepping noticeably smoother. Drop it (10000 or and makes stepping noticeably smoother. Drop it (10000 or
lower) if the link is flaky or you are using long dupont lower) if the link is flaky or you are using long dupont
wires instead of the probe's own connector. wires instead of the probe's own connector.
USE_CORE Which cores to expose to the client. Default: 0 (core0 only). USE_CORE Which cores to expose to the client. Default: 0 (core0 only).
Accepted values: Accepted values:
0 core0 only <- use this with Binary Ninja 0 core0 only <- use this with Binary Ninja
1 core1 only <- rarely useful 1 core1 only <- rarely useful
SMP both cores as hwthreads <- see "Why USE_CORE=0" SMP both cores as hwthreads <- see "Why USE_CORE=0"
Do not change this to SMP when driving Binary Ninja. The Do not change this to SMP when driving Binary Ninja. The
explanation below is the whole reason this default is 0. explanation below is the whole reason this default is 0.
BP_ADDR OPTIONAL address to halt at during the startup run, as 0x BP_ADDR OPTIONAL address to halt at during the startup run, as 0x
prefixed hex, e.g. 0x10000234 for main. Unset by default, prefixed hex, e.g. 0x10000234 for main. Unset by default,
which is the normal "attach to a running target" behaviour. which is the normal "attach to a running target" behaviour.
Arms a 2-byte hardware execute breakpoint just before the Arms a 2-byte hardware execute breakpoint just before the
final "reset run", so the core runs from the vector table final "reset run", so the core runs from the vector table
and stops there on its own, with no client attached yet. and stops there on its own, with no client attached yet.
See "Why BP_ADDR is one-shot" below for the important See "Why BP_ADDR is one-shot" below for the important
limitation. Arming a length of 2 is mandatory: the Cortex-M33 limitation. Arming a length of 2 is mandatory: the Cortex-M33
comparators are halfword-based and reject anything else. comparators are halfword-based and reject anything else.
.NOTES .NOTES
Requirements: Requirements:
* Pico Debug Probe (or any CMSIS-DAP / SWD adapter) connected to the target. * Pico Debug Probe (or any CMSIS-DAP / SWD adapter) connected to the target.
* OpenOCD with the rp2350 target script installed. See PICO_OPENOCD. * OpenOCD with the rp2350 target script installed. See PICO_OPENOCD.
* Exactly one process may own the debug probe. * Exactly one process may own the debug probe.
* A firmware image already programmed into flash (use flash.ps1 first). * A firmware image already programmed into flash (use flash.ps1 first).
* The Debug Probe must use the WinUSB driver. If OpenOCD reports * The Debug Probe must use the WinUSB driver. If OpenOCD reports
"unable to open CMSIS-DAP device", install it with Zadig "unable to open CMSIS-DAP device", install it with Zadig
(https://zadig.akeo.ie/), selecting "Debug Probe (CMSIS-DAP)" -> WinUSB. (https://zadig.akeo.ie/), selecting "Debug Probe (CMSIS-DAP)" -> WinUSB.
Why USE_CORE=0 (core1 must be hidden from the client) Why USE_CORE=0 (core1 must be hidden from the client)
The RP2350 has two Cortex-M33 cores. Core1 does not start on its own: The RP2350 has two Cortex-M33 cores. Core1 does not start on its own:
nothing in a Pico SDK application releases it from reset unless the program nothing in a Pico SDK application releases it from reset unless the program
explicitly does so. If you expose it anyway (USE_CORE=SMP), its registers explicitly does so. If you expose it anyway (USE_CORE=SMP), its registers
read back as meaningless reset defaults: read back as meaningless reset defaults:
core1: pc 0x000000ec sp 0xf0000000 xpsr 0x09000000 lr 0x00000147 core1: pc 0x000000ec sp 0xf0000000 xpsr 0x09000000 lr 0x00000147
core0: pc 0x1000320c sp 0x20081f38 xpsr 0xa9000000 lr 0x100030ab core0: pc 0x1000320c sp 0x20081f38 xpsr 0xa9000000 lr 0x100030ab
Binary Ninja's register widget renders a memory preview for every register, Binary Ninja's register widget renders a memory preview for every register,
which means it treats each register value as an ADDRESS and reads it. The which means it treats each register value as an ADDRESS and reads it. The
core1 values above are not real addresses. Each read data-aborts, and core1 values above are not real addresses. Each read data-aborts, and
OpenOCD responds by tearing down and re-establishing the SWD debug port, OpenOCD responds by tearing down and re-establishing the SWD debug port,
logging a pair of lines per fault: logging a pair of lines per fault:
Error: Failed to read memory at 0xf0000000 Error: Failed to read memory at 0xf0000000
Info : SWD DPIDR 0x4c013477 Info : SWD DPIDR 0x4c013477
That becomes a self-sustaining loop of roughly 450 fault-and-recover cycles That becomes a self-sustaining loop of roughly 450 fault-and-recover cycles
every two seconds, which makes the session unusable. It looks exactly like a every two seconds, which makes the session unusable. It looks exactly like a
broken debugger or a broken firmware. It is neither: it is a configuration broken debugger or a broken firmware. It is neither: it is a configuration
mismatch, and hiding core1 removes it completely. mismatch, and hiding core1 removes it completely.
Why reset run (the target must be released, not halted) Why reset run (the target must be released, not halted)
On RP2350, halting during reset stops the core at the boot ROM stub BEFORE On RP2350, halting during reset stops the core at the boot ROM stub BEFORE
the stack pointer is loaded: the stack pointer is loaded:
xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000 lr: 0xffffffff xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000 lr: 0xffffffff
Those values are garbage for every core, including core0. Attaching in that Those values are garbage for every core, including core0. Attaching in that
window triggers the identical fault storm described above. Ending this window triggers the identical fault storm described above. Ending this
script with "reset run" means the core starts from the vector table and is script with "reset run" means the core starts from the vector table and is
executing normally by the time you attach, so registers read back correct. executing normally by the time you attach, so registers read back correct.
Consequence for the client: ATTACH WHILE THE TARGET IS RUNNING. Do not Consequence for the client: ATTACH WHILE THE TARGET IS RUNNING. Do not
press Reset/Restart in Binary Ninja -- it performs reset-halt and puts you press Reset/Restart in Binary Ninja -- it performs reset-halt and puts you
back in the garbage window. If you must reset, send "reset run" over the back in the garbage window. If you must reset, send "reset run" over the
OpenOCD telnet port (4444) instead. See WEEK04\WEEK04-BN.md. OpenOCD telnet port (4444) instead. See WEEK04\WEEK04-BN.md.
Why BP_ADDR is one-shot (read this before relying on it) Why BP_ADDR is one-shot (read this before relying on it)
A breakpoint armed here DOES fire during the startup "reset run" and halts A breakpoint armed here DOES fire during the startup "reset run" and halts
the core at your address, so the server comes up parked there and your the core at your address, so the server comes up parked there and your
debugger can simply attach and look at it. That part works. debugger can simply attach and look at it. That part works.
What you do NOT get is a reusable breakpoint. As soon as any GDB client What you do NOT get is a reusable breakpoint. As soon as any GDB client
connects, OpenOCD unconditionally flushes every breakpoint it is holding: connects, OpenOCD unconditionally flushes every breakpoint it is holding:
Info : accepting 'gdb' connection on tcp/3333 Info : accepting 'gdb' connection on tcp/3333
Debug: breakpoints.c:328 breakpoint_remove_all_internal(): Debug: breakpoints.c:328 breakpoint_remove_all_internal():
[rp2350.dap.core0] Delete all breakpoints [rp2350.dap.core0] Delete all breakpoints
So by the time Binary Ninja is up, the comparator is gone -- reading So by the time Binary Ninja is up, the comparator is gone -- reading
0xE0002000 shows zeros, not your address. Consequences: 0xE0002000 shows zeros, not your address. Consequences:
* The startup stop is single-use. You cannot Resume and re-catch the * The startup stop is single-use. You cannot Resume and re-catch the
same address. same address.
* You cannot use BP_ADDR to stop in a loop that is already running, * You cannot use BP_ADDR to stop in a loop that is already running,
because the core only passes that point once per reset. because the core only passes that point once per reset.
* main (0x10000234) is a good BP_ADDR value precisely because it is * main (0x10000234) is a good BP_ADDR value precisely because it is
reached exactly once, right after reset. reached exactly once, right after reset.
To arm anything further, or to re-arm main, do it from the OpenOCD command To arm anything further, or to re-arm main, do it from the OpenOCD command
port AFTER your debugger has connected -- the order is the whole trick: port AFTER your debugger has connected -- the order is the whole trick:
nc 127.0.0.1 4444 nc 127.0.0.1 4444
> bp 0x1000023e 2 hw > bp 0x1000023e 2 hw
> reset run > reset run
Arming before the client connects does not work (flushed above), and in Arming before the client connects does not work (flushed above), and in
plain GDB the equivalent "hbreak" is cleared by "detach" -- both were plain GDB the equivalent "hbreak" is cleared by "detach" -- both were
verified by reading the FPB comparator registers back. verified by reading the FPB comparator registers back.
Related Binary Ninja bug: Binary Ninja's own breakpoints cannot be used on Related Binary Ninja bug: Binary Ninja's own breakpoints cannot be used on
this target at all. It sends Z0,<addr>,1 -- a 1-byte packet -- and this target at all. It sends Z0,<addr>,1 -- a 1-byte packet -- and
OpenOCD answers "only breakpoints of two bytes length supported". Both OpenOCD answers "only breakpoints of two bytes length supported". Both
Toggle Breakpoint (F2) and Add Hardware Breakpoint (F3) fail, at every Toggle Breakpoint (F2) and Add Hardware Breakpoint (F3) fail, at every
address, and the dialog's Size field is disabled so there is no UI way address, and the dialog's Size field is disabled so there is no UI way
around it. gdb_breakpoint_override hard does not change this. Hence the around it. gdb_breakpoint_override hard does not change this. Hence the
command-port workflow described above. command-port workflow described above.
Why the remaining OpenOCD flags are set Why the remaining OpenOCD flags are set
gdb_breakpoint_override hard gdb_breakpoint_override hard
Force every client breakpoint onto the Cortex-M33 hardware comparators Force every client breakpoint onto the Cortex-M33 hardware comparators
(the RP2350 has 8 breakpoints and 4 watchpoints). Without this, a (the RP2350 has 8 breakpoints and 4 watchpoints). Without this, a
client may try to write a BKPT instruction into flash at 0x10000000, client may try to write a BKPT instruction into flash at 0x10000000,
which is read-only XIP memory, and the write fails. which is read-only XIP memory, and the write fails.
gdb_memory_map disable gdb_memory_map disable
Stops the client probing the entire 32 MiB flash map on connect. Pure Stops the client probing the entire 32 MiB flash map on connect. Pure
Raspberry Pi guidance for suppressing spurious "Failed to read memory" Raspberry Pi guidance for suppressing spurious "Failed to read memory"
reports during target discovery. reports during target discovery.
cortex_m reset_config sysresetreq cortex_m reset_config sysresetreq
The Cortex-M33 in the RP2350 has no VECTRESET. Without this, OpenOCD The Cortex-M33 in the RP2350 has no VECTRESET. Without this, OpenOCD
warns on every reset: warns on every reset:
VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ
instead instead
NOTE: this MUST be the generic "cortex_m" command, not NOTE: this MUST be the generic "cortex_m" command, not
"rp2350.dap.core1 cortex_m ...". With USE_CORE=0 the core1 target does "rp2350.dap.core1 cortex_m ...". With USE_CORE=0 the core1 target does
not exist, so a core1-scoped command aborts OpenOCD before "init" runs, not exist, so a core1-scoped command aborts OpenOCD before "init" runs,
and the script exits silently having printed nothing useful. and the script exits silently having printed nothing useful.
adapter speed adapter speed
See ADAPTER_SPEED above. See ADAPTER_SPEED above.
.EXAMPLE .EXAMPLE
.\debug-server.ps1 .\debug-server.ps1
.EXAMPLE .EXAMPLE
$env:ADAPTER_SPEED=10000; .\debug-server.ps1 $env:ADAPTER_SPEED=10000; .\debug-server.ps1
.EXAMPLE .EXAMPLE
$env:PICO_OPENOCD="C:\openocd\bin"; .\debug-server.ps1 $env:PICO_OPENOCD="C:\openocd\bin"; .\debug-server.ps1
.EXAMPLE .EXAMPLE
$env:BP_ADDR="0x10000234"; .\debug-server.ps1 $env:BP_ADDR="0x10000234"; .\debug-server.ps1
Comes up halted at main (one-shot; see "Why BP_ADDR is one-shot"). Comes up halted at main (one-shot; see "Why BP_ADDR is one-shot").
.NOTES .NOTES
Exit status: Exit status:
* propagated from OpenOCD. A clean shutdown via Ctrl-C exits 0; an * propagated from OpenOCD. A clean shutdown via Ctrl-C exits 0; an
OpenOCD configuration error exits non-zero. OpenOCD configuration error exits non-zero.
Related scripts: Related scripts:
flash.ps1 one-shot raw .bin programmer (exits when done) flash.ps1 one-shot raw .bin programmer (exits when done)
See also: See also:
WEEK04\WEEK04-BN.md the full walkthrough this script belongs to WEEK04\WEEK04-BN.md the full walkthrough this script belongs to
#> #>
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter()] [Parameter()]
[string]$OCD [string]$OCD
) )
Set-StrictMode -Version Latest Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
# --- configuration --------------------------------------------------------- # --- configuration ---------------------------------------------------------
if (-not $OCD) { $OCD = $env:PICO_OPENOCD } if (-not $OCD) { $OCD = $env:PICO_OPENOCD }
if (-not $OCD) { $OCD = "$env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev" } if (-not $OCD) { $OCD = "$env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev" }
$SPEED = if ($env:ADAPTER_SPEED) { $env:ADAPTER_SPEED } else { "24000" } $SPEED = if ($env:ADAPTER_SPEED) { $env:ADAPTER_SPEED } else { "24000" }
$USE_CORE = if ($env:USE_CORE) { $env:USE_CORE } else { "0" } $USE_CORE = if ($env:USE_CORE) { $env:USE_CORE } else { "0" }
$BP_ADDR = if ($env:BP_ADDR) { $env:BP_ADDR.Trim() } else { "" } $BP_ADDR = if ($env:BP_ADDR) { $env:BP_ADDR.Trim() } else { "" }
if ($BP_ADDR -and $BP_ADDR -notmatch '^0x[0-9a-fA-F]+$') { if ($BP_ADDR -and $BP_ADDR -notmatch '^0x[0-9a-fA-F]+$') {
Write-Error "BP_ADDR must be 0x-prefixed hex, e.g. 0x10000234 (got '$BP_ADDR')" Write-Error "BP_ADDR must be 0x-prefixed hex, e.g. 0x10000234 (got '$BP_ADDR')"
exit 1 exit 1
} }
if (-not (Test-Path "$OCD\openocd.exe")) { if (-not (Test-Path "$OCD\openocd.exe")) {
Write-Error "OpenOCD not found at $OCD\openocd.exe (set PICO_OPENOCD or -OCD to the directory containing openocd.exe)" Write-Error "OpenOCD not found at $OCD\openocd.exe (set PICO_OPENOCD or -OCD to the directory containing openocd.exe)"
exit 1 exit 1
} }
# --- announce, so the operator can verify intent before the target is touched -- # --- announce, so the operator can verify intent before the target is touched --
Write-Host "Starting OpenOCD GDB server on 127.0.0.1:3333 using $OCD\openocd.exe" Write-Host "Starting OpenOCD GDB server on 127.0.0.1:3333 using $OCD\openocd.exe"
Write-Host "SWD adapter speed: $SPEED kHz" Write-Host "SWD adapter speed: $SPEED kHz"
Write-Host "Cores exposed to GDB (USE_CORE): $USE_CORE" Write-Host "Cores exposed to GDB (USE_CORE): $USE_CORE"
Write-Host "Target will be reset and released (reset run) - attach while it is running." Write-Host "Target will be reset and released (reset run) - attach while it is running."
if ($BP_ADDR) { if ($BP_ADDR) {
Write-Host "Startup breakpoint at $BP_ADDR (2-byte hardware execute, one-shot)." Write-Host "Startup breakpoint at $BP_ADDR (2-byte hardware execute, one-shot)."
Write-Host " It fires during this startup reset run. Any client connecting later" Write-Host " It fires during this startup reset run. Any client connecting later"
Write-Host " causes OpenOCD to delete it, so arm further breakpoints on port 4444" Write-Host " causes OpenOCD to delete it, so arm further breakpoints on port 4444"
Write-Host " after attaching: bp <addr> 2 hw" Write-Host " after attaching: bp <addr> 2 hw"
} }
# --- start ----------------------------------------------------------------- # --- start -----------------------------------------------------------------
# #
# Order matters: USE_CORE must be set BEFORE -f target/rp2350.cfg is read, # Order matters: USE_CORE must be set BEFORE -f target/rp2350.cfg is read,
# because the target script branches on it when creating the DAP targets. # because the target script branches on it when creating the DAP targets.
# #
# "reset run" is last so it happens after init and after the target is # "reset run" is last so it happens after init and after the target is
# examined, releasing the core rather than halting it. See .NOTES for why. # examined, releasing the core rather than halting it. See .NOTES for why.
# #
# Any BP_ADDR breakpoint is inserted after "init" (the target must exist before # Any BP_ADDR breakpoint is inserted after "init" (the target must exist before
# a comparator can be programmed) but before "reset run" (so the core is already # a comparator can be programmed) but before "reset run" (so the core is already
# armed when it starts). The length must be 2: Cortex-M33 comparators reject # armed when it starts). The length must be 2: Cortex-M33 comparators reject
# other widths. # other widths.
$ocdArgs = @( $ocdArgs = @(
"-s", "$OCD\scripts", "-s", "$OCD\scripts",
"-f", "interface/cmsis-dap.cfg", "-f", "interface/cmsis-dap.cfg",
"-c", "set USE_CORE $USE_CORE", "-c", "set USE_CORE $USE_CORE",
"-f", "target/rp2350.cfg", "-f", "target/rp2350.cfg",
# Drop the hwthread RTOS the RP2350 target script attaches to core0. # Drop the hwthread RTOS the RP2350 target script attaches to core0.
# #
# target/rp2350.cfg creates core0 with "-rtos hwthread", which registers a # target/rp2350.cfg creates core0 with "-rtos hwthread", which registers a
# fake RTOS whose "current thread" is coreid+1 = 1. Binary Ninja single-steps # fake RTOS whose "current thread" is coreid+1 = 1. Binary Ninja single-steps
# with the GDB packet "vCont;s" and no thread id, i.e. thread 0. OpenOCD's # with the GDB packet "vCont;s" and no thread id, i.e. thread 0. OpenOCD's
# gdb_server sees rtos->current_thread (1) != thread_id (0) and takes its # gdb_server sees rtos->current_thread (1) != thread_id (0) and takes its
# "fake step" path, replying with a stop without ever stepping the core: # "fake step" path, replying with a stop without ever stepping the core:
# #
# gdb_server.c gdb_handle_vcont_packet(): fake step thread 0 # gdb_server.c gdb_handle_vcont_packet(): fake step thread 0
# #
# The result is that Step Into / Step Over in Binary Ninja does nothing: the # The result is that Step Into / Step Over in Binary Ninja does nothing: the
# PC never moves. Clearing the RTOS removes the mismatch so the step is real. # PC never moves. Clearing the RTOS removes the mismatch so the step is real.
# Harmless for single-core use, which is all this lab does (USE_CORE=0). # Harmless for single-core use, which is all this lab does (USE_CORE=0).
# The core's name differs between OpenOCD builds (rp2350.dap.core0 vs rp2350.cm0 # The core's name differs between OpenOCD builds (rp2350.dap.core0 vs rp2350.cm0
# in the Pico SDK's Windows build), so look it up instead of hard-coding it. # in the Pico SDK's Windows build), so look it up instead of hard-coding it.
"-c", "[lindex [target names] 0] configure -rtos none", "-c", "[lindex [target names] 0] configure -rtos none",
"-c", "adapter speed $SPEED", "-c", "adapter speed $SPEED",
"-c", "gdb_memory_map disable", "-c", "gdb_memory_map disable",
"-c", "gdb_breakpoint_override hard", "-c", "gdb_breakpoint_override hard",
"-c", "cortex_m reset_config sysresetreq", "-c", "cortex_m reset_config sysresetreq",
"-c", "init" "-c", "init"
) )
if ($BP_ADDR) { if ($BP_ADDR) {
$ocdArgs += @("-c", "bp $BP_ADDR 2 hw") $ocdArgs += @("-c", "bp $BP_ADDR 2 hw")
} }
$ocdArgs += @("-c", "reset run") $ocdArgs += @("-c", "reset run")
& "$OCD\openocd.exe" @ocdArgs & "$OCD\openocd.exe" @ocdArgs
exit $LASTEXITCODE exit $LASTEXITCODE
+132 -132
View File
@@ -1,132 +1,132 @@
<# <#
.SYNOPSIS .SYNOPSIS
Program a raw .bin into RP2350 XIP flash via the Pico Debug Probe and OpenOCD. Program a raw .bin into RP2350 XIP flash via the Pico Debug Probe and OpenOCD.
.DESCRIPTION .DESCRIPTION
Writes a headerless raw binary to the RP2350's external XIP flash starting at Writes a headerless raw binary to the RP2350's external XIP flash starting at
physical address 0x10000000, verifies the written bytes by reading them back, physical address 0x10000000, verifies the written bytes by reading them back,
then releases the core so the freshly programmed firmware runs. then releases the core so the freshly programmed firmware runs.
A raw .bin carries no address information, no entry point and no section A raw .bin carries no address information, no entry point and no section
table, so the load address MUST be supplied out of band. On the RP2350 the table, so the load address MUST be supplied out of band. On the RP2350 the
only correct value is 0x10000000: that is where the boot ROM jumps after only correct value is 0x10000000: that is where the boot ROM jumps after
pulling the reset vector out of the on-chip XIP window. Flashing anywhere pulling the reset vector out of the on-chip XIP window. Flashing anywhere
else produces a board that enumerates over USB and then does nothing. else produces a board that enumerates over USB and then does nothing.
The target must already be running the stock RP2350 bootrom (the default The target must already be running the stock RP2350 bootrom (the default
state after power-up, or after any BOOTSEL + UF2 reflash). OpenOCD attaches state after power-up, or after any BOOTSEL + UF2 reflash). OpenOCD attaches
to the bootrom over SWD, halts it, programs flash, verifies, and resets. to the bootrom over SWD, halts it, programs flash, verifies, and resets.
This is the macOS / Linux equivalent of flash.sh. The two must stay in This is the macOS / Linux equivalent of flash.sh. The two must stay in
lockstep: same base address, same verify, same conservative SWD clock. lockstep: same base address, same verify, same conservative SWD clock.
.PARAMETER Bin .PARAMETER Bin
Mandatory. Path to the raw .bin image to program. Mandatory. Path to the raw .bin image to program.
.ENVIRONMENT .ENVIRONMENT
PICO_OPENOCD Directory containing openocd.exe AND its scripts\ directory. PICO_OPENOCD Directory containing openocd.exe AND its scripts\ directory.
Default: $env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev Default: $env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev
The path is used for BOTH the executable and the -s scripts The path is used for BOTH the executable and the -s scripts
argument. argument.
ADAPTER_SPEED SWD clock in kHz. Default: 5000. ADAPTER_SPEED SWD clock in kHz. Default: 5000.
5000 kHz is deliberately conservative. This is a write path, 5000 kHz is deliberately conservative. This is a write path,
not a read-only debug session, and a marginal USB cable or not a read-only debug session, and a marginal USB cable or
long dupont run produces spurious verify failures at higher long dupont run produces spurious verify failures at higher
clocks. Raise it (24000) for read-only work; if clocks. Raise it (24000) for read-only work; if
"Error: target not halted" or verify mismatches appear, "Error: target not halted" or verify mismatches appear,
lower it to 1000. lower it to 1000.
.EXAMPLE .EXAMPLE
.\flash.ps1 -Bin 0x0005_intro-to-variables\build\0x0005_intro-to-variables.bin .\flash.ps1 -Bin 0x0005_intro-to-variables\build\0x0005_intro-to-variables.bin
.EXAMPLE .EXAMPLE
$env:ADAPTER_SPEED=1000; .\flash.ps1 -Bin build\hacked.bin $env:ADAPTER_SPEED=1000; .\flash.ps1 -Bin build\hacked.bin
.EXAMPLE .EXAMPLE
$env:PICO_OPENOCD="C:\openocd\bin"; .\flash.ps1 -Bin build\hacked.bin $env:PICO_OPENOCD="C:\openocd\bin"; .\flash.ps1 -Bin build\hacked.bin
.NOTES .NOTES
Requirements: Requirements:
* Pico Debug Probe (or any CMSIS-DAP / SWD adapter) connected to the target. * Pico Debug Probe (or any CMSIS-DAP / SWD adapter) connected to the target.
* OpenOCD with the rp2350 target script installed. * OpenOCD with the rp2350 target script installed.
* The Debug Probe must use the WinUSB driver. If OpenOCD reports * The Debug Probe must use the WinUSB driver. If OpenOCD reports
"unable to open CMSIS-DAP device", install it with Zadig "unable to open CMSIS-DAP device", install it with Zadig
(https://zadig.akeo.ie/), selecting "Debug Probe (CMSIS-DAP)" -> WinUSB. (https://zadig.akeo.ie/), selecting "Debug Probe (CMSIS-DAP)" -> WinUSB.
* Exactly one process may own the debug probe. Close any other OpenOCD, * Exactly one process may own the debug probe. Close any other OpenOCD,
GDB, or IDE debug session first. GDB, or IDE debug session first.
Exit status: Exit status:
0 flash written, verified, and core released 0 flash written, verified, and core released
1 input file missing or OpenOCD not found 1 input file missing or OpenOCD not found
* any other status is propagated from OpenOCD, so a failed verify or a * any other status is propagated from OpenOCD, so a failed verify or a
write error is visible to the caller rather than being swallowed. write error is visible to the caller rather than being swallowed.
Related scripts: Related scripts:
debug-server.ps1 long-running GDB server for live debugging with debug-server.ps1 long-running GDB server for live debugging with
Binary Ninja. Use that instead of this script when you Binary Ninja. Use that instead of this script when you
need to single-step. need to single-step.
See also: See also:
WEEK04\WEEK04-BN.md the full walkthrough this script belongs to WEEK04\WEEK04-BN.md the full walkthrough this script belongs to
#> #>
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()] [ValidateNotNullOrEmpty()]
[string]$Bin [string]$Bin
) )
Set-StrictMode -Version Latest Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
# --- argument validation --------------------------------------------------- # --- argument validation ---------------------------------------------------
if (-not (Test-Path -PathType Leaf $Bin)) { if (-not (Test-Path -PathType Leaf $Bin)) {
Write-Error "file not found: $Bin" Write-Error "file not found: $Bin"
Write-Host "build it first: cmake -B build -G Ninja -DPICO_BOARD=pico2 -DPICO_PLATFORM=rp2350 ; cmake --build build" Write-Host "build it first: cmake -B build -G Ninja -DPICO_BOARD=pico2 -DPICO_PLATFORM=rp2350 ; cmake --build build"
exit 1 exit 1
} }
# --- toolchain resolution -------------------------------------------------- # --- toolchain resolution --------------------------------------------------
$OCD = if ($env:PICO_OPENOCD) { $env:PICO_OPENOCD } else { "$env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev" } $OCD = if ($env:PICO_OPENOCD) { $env:PICO_OPENOCD } else { "$env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev" }
if (-not (Test-Path "$OCD\openocd.exe")) { if (-not (Test-Path "$OCD\openocd.exe")) {
Write-Error "OpenOCD not found at $OCD\openocd.exe (set PICO_OPENOCD to the directory containing openocd.exe)" Write-Error "OpenOCD not found at $OCD\openocd.exe (set PICO_OPENOCD to the directory containing openocd.exe)"
exit 1 exit 1
} }
$SPEED = if ($env:ADAPTER_SPEED) { $env:ADAPTER_SPEED } else { "5000" } $SPEED = if ($env:ADAPTER_SPEED) { $env:ADAPTER_SPEED } else { "5000" }
# --- program --------------------------------------------------------------- # --- program ---------------------------------------------------------------
# OpenOCD flag notes: # OpenOCD flag notes:
# -f interface/cmsis-dap.cfg the Pico Debug Probe is a CMSIS-DAP v1 device # -f interface/cmsis-dap.cfg the Pico Debug Probe is a CMSIS-DAP v1 device
# -f target/rp2350.cfg RP2350 dual Cortex-M33 + RP2350B0-style DAP; # -f target/rp2350.cfg RP2350 dual Cortex-M33 + RP2350B0-style DAP;
# sets USE_CORE=SMP by default, which is fine here # sets USE_CORE=SMP by default, which is fine here
# because we never hand uninitialised core1 # because we never hand uninitialised core1
# registers to a debugger. For live debugging use # registers to a debugger. For live debugging use
# debug-server.ps1, which forces USE_CORE=0. # debug-server.ps1, which forces USE_CORE=0.
# -c "program BIN 0x10000000 verify reset exit" # -c "program BIN 0x10000000 verify reset exit"
# program the write # program the write
# 0x10000000 base address (see .DESCRIPTION) # 0x10000000 base address (see .DESCRIPTION)
# verify read back and compare every byte; a mismatch aborts # verify read back and compare every byte; a mismatch aborts
# reset reset the core so the new image starts at its vectors # reset reset the core so the new image starts at its vectors
# exit release the probe and return to the shell # exit release the probe and return to the shell
# #
# The adapter speed is deliberately lower here than in debug-server.ps1; see # The adapter speed is deliberately lower here than in debug-server.ps1; see
# ADAPTER_SPEED in .ENVIRONMENT. # ADAPTER_SPEED in .ENVIRONMENT.
Write-Host "Flashing $Bin -> 0x10000000 using $OCD\openocd.exe (SWD $SPEED kHz)" Write-Host "Flashing $Bin -> 0x10000000 using $OCD\openocd.exe (SWD $SPEED kHz)"
# OpenOCD parses -c strings as Tcl, which eats backslashes ("\build" -> backspace+"uild"). # OpenOCD parses -c strings as Tcl, which eats backslashes ("\build" -> backspace+"uild").
# Hand it an absolute path with forward slashes, braced so spaces survive. # Hand it an absolute path with forward slashes, braced so spaces survive.
$BinTcl = (Resolve-Path $Bin).Path -replace '\\', '/' $BinTcl = (Resolve-Path $Bin).Path -replace '\\', '/'
& "$OCD\openocd.exe" ` & "$OCD\openocd.exe" `
-s "$OCD\scripts" ` -s "$OCD\scripts" `
-f interface/cmsis-dap.cfg ` -f interface/cmsis-dap.cfg `
-f target/rp2350.cfg ` -f target/rp2350.cfg `
-c "adapter speed $SPEED" ` -c "adapter speed $SPEED" `
-c "program {$BinTcl} 0x10000000 verify reset exit" -c "program {$BinTcl} 0x10000000 verify reset exit"
exit $LASTEXITCODE exit $LASTEXITCODE