Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
pico2-swd-riscv | Kitploit
Herramientas/GitHubGitHub/jackdoe/pico2-swd-riscv
Seguridad de Sistemas EmbebidosIngeniería InversaDepuradoresHacking de HardwareSeguridad de HardwareAnálisis de Firmware
GitHubjackdoe/pico2-swd-riscv

pico2-swd-riscv

Ver Repositorio
853hace 6 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

pico2-swd-riscv

Sonda de depuración SWD para núcleos RISC-V (Hazard3) de RP2350. Un Pico2 depura a otro mediante dos cables GPIO.

0. ADVERTENCIA DE CÓDIGO VIBE (ESCRITO POR UN HUMANO)

Aproximadamente el 80% del código es código vibe; el readme está casi completamente generado (excepto toda la sección de advertencia de código vibe). Pasé muchas noches con el osciloscopio y la documentación e hice un prototipo funcional que podía hacer sba/lectura/escritura de registros, comandos abstractos y progbuf; el resto se hizo con claude code. Los tests son una suite de pruebas bastante completa y uso el núcleo de la librería en mis propios proyectos, pero, como dicen, «hic sunt dracones». También leí el readme y el código y no noté nada incorrecto (y eliminé las partes incorrectas/poco claras).

Este proyecto fue mi caso de estudio sobre vibecoding en un proyecto más complicado que no entiendo al 100% y para el que no hay ningún código existente obvio que pueda «usarse». Empezó como ~1000 líneas de código que escribí y conocía muy bien, leyendo la documentación de rp2350, arm swd y riscv debug, capturando datos con osciloscopio y openocd, decodificándolos y analizando la secuencia de wakeup y luego los comandos de lectura/escritura. Cuando lo hice funcionar, se lo di a claude para que lo convirtiera en una librería que pudiera usar en otros proyectos, y luego lo fui construyendo poco a poco.

Después de unas 3-4k líneas de código perdí por completo el hilo de lo que estaba pasando, y ya no consideraría que este código lo he escrito yo, pero añadir más y más tests resultaba «agradable», o al menos reconfortante.

Hubo algo de gaslighting, sobre todo cuando malinterpretó dap_read_mem32 pensando que leía de la RAM y no el protocolo MEM-AP TAR/DRW/RDBUFF, lo que condujo a una cantidad increíble de disparates.

En general diría que fue una experiencia horrible. Aunque tardé 10 horas en escribir cerca de 10000 líneas de código, no considero este proyecto como mío, y no tengo sensación de logro ni de crecimiento.

En contraste, usar IA para leer toda la documentación (que son miles de páginas) y escribir scripts útiles para decodificar los datos del osciloscopio, crear structs de C empaquetadas a partir de la documentación, etc., fue muy agradable, y sí me sentí bien después. En el momento en que leí el primer registro y luego, cuando pude leer memoria vía SBA, me sentí increíble.

El problema principal es el gusto: cuando escribo código siento si es bueno o malo; mientras lo escribo, sé si está mal, pero usando claude code me insensibilizo muy rápido y simplemente no puedo distinguirlo. «Se lee» bien, pero no sé cómo se siente. En este caso ocurrió cuando el código creció unas 4 veces, de 1k a 4k líneas. Y lo peor de todo: mi modelo mental del código ha desaparecido por completo, y con él, mi sentido de propiedad.

Los tokens no tienen razón ni propósito, lo que hace que leer código sea ridículamente difícil, ya que cada token puede ser un completo disparate. Al leer código humano, los símbolos tienen un propósito: alguien pensó «pondré esto en una variable, luego comprobaré su estado», así que finjo ser esa persona y pienso por qué habrán escrito esto. Poco después lo entiendo, porque son humanos y yo soy humano. Pero los símbolos de la IA no tienen razón, y lo peor de todo es que todos parecen engañosamente correctos, así que tengo que pensar 10 veces más para saber si está mal. Con cualquier código humano (incluido el tuyo propio) es bastante fácil calibrar cuánto puedes confiar en él, y es bastante consistente. Con el código de la IA, una función puede ser mucho mejor de lo que tú habrías escrito, y el código 2 líneas más abajo puede ser porquería de culto cargo que se ve increíblemente bien, pero es estructuralmente incorrecta.

Al final diría que he adquirido un buen entendimiento de los cables, los tiempos y la mecánica de bajo nivel de ap/dp, sba y progbuf, pero me arrepiento de no haber escrito todo yo mismo, aunque me hubiera llevado 10 veces más tiempo.

Odio esto, joder.

Y no puedo evitar sentir asco y vergüenza. ¿Es esto lo que es programar ahora? De verdad espero que esto sea una etapa intermedia y que cambie para mejor. El problema es que no sé qué es «mejor»: para algunos parece ser no escribir el código, para otros no modelar el problema y para un tercer grupo no tener que pensar. En mi caso, no estoy seguro. Sí quiero crear cosas, y muchas veces no quiero saber algo, sino usarlo; por ejemplo, el controlador de host USB del rp2350: la forma en que tienes que rearmar las interrupciones y cómo se comparte el registro epx es súper molesta, probablemente por buenas razones, pero yo solo quiero usarlo para hacer mi driver CBI.

Supongo que la pregunta es qué es lo que quiero crear, porque puedes subir mucho en la pila: desde los registros del chip USB hasta CBI, UFI, FAT16 y el sistema operativo del ordenador retro que estoy construyendo; pero ¿por qué parar? ¿Hacer los esquemáticos, los PCB, los archivos CAD, quizás enviarlo automáticamente a la fábrica y luego simplemente enviármelo? ¿Pero por qué parar? ¿Hacer mi tienda web, empezar a vender, crear una comunidad, anuncios, marketing, generar algunos vídeos de unboxing, quizás algunos memes virales? ¿Procesar los pedidos directamente a la fábrica, bajo demanda, y si hay algún problema, que esté listo con atención al cliente?

¿Qué hago mientras tanto? ¿Sentarme en la playa? Odio la playa.

¿Dónde se detiene?

PD: como dijo el poeta: el precio de conseguir lo que quieres es conseguir lo que una vez quisiste.

Arquitectura

root@kitploit:~
Application
    |
rp2350.c    RISC-V Debug Module (halt/resume/step, registers, memory, trace)
    |
dap.c       Debug Access Port (DP/AP registers, bank caching, MEM-AP)
    |
swd_protocol.c  SWD wire protocol (PIO bit-banging, packet encoding, retry)
    |
swd.pio     PIO state machine (4-cycle SWCLK, bidirectional SWDIO)

Cada capa mantiene su propio estado y se comunica únicamente con su vecina.

Uso

root@kitploit:~
swd_config_t config = swd_config_default();
config.pin_swclk = 2;
config.pin_swdio = 3;

swd_target_t *target = swd_target_create(&config);
swd_connect(target);
rp2350_init(target);

rp2350_halt(target, 0);
swd_result_t pc = rp2350_read_pc(target, 0);
rp2350_resume(target, 0);

swd_target_destroy(target);

Control del Hart

root@kitploit:~
rp2350_halt(target, 0);
rp2350_step(target, 0);
rp2350_resume(target, 0);
rp2350_reset(target, 0, true);

swd_result_t pc = rp2350_read_pc(target, 0);
rp2350_write_pc(target, 0, 0x20000000);

swd_result_t val = rp2350_read_reg(target, 0, 5);
rp2350_write_reg(target, 0, 5, 0xDEADBEEF);

uint32_t regs[32];
rp2350_read_all_regs(target, 0, regs);

swd_result_t csr = rp2350_read_csr(target, 0, 0x300);
rp2350_write_csr(target, 0, 0x300, value);

Ambos harts (0 y 1) se controlan de forma independiente.

Acceso a Memoria

No intrusivo mediante System Bus Access. Funciona mientras el hart está en ejecución.

root@kitploit:~
swd_result_t val = rp2350_read_mem32(target, 0x20000000);
rp2350_write_mem32(target, 0x20000000, 0xDEADBEEF);

rp2350_read_mem16(target, addr);
rp2350_write_mem8(target, addr, byte);

uint32_t buf[256];
rp2350_read_mem_block(target, 0x20000000, buf, 256);
rp2350_write_mem_block(target, 0x20000000, buf, 256);

Las transferencias por bloques usan autoincremento SBA para mayor rendimiento.

Ejecución de Código

root@kitploit:~
const uint32_t program[] = {
    0x200415b7,  // lui  a1, 0x20040
    0xabcd0537,  // lui  a0, 0xabcd0
    0x00a5a223,  // sw   a0, 4(a1)
    0x0000006f,  // j    . (loop)
};

rp2350_execute_code(target, 0, 0x20000000, program, 4);

Sube a la SRAM de destino, verifica, establece el PC y reanuda.

Trazado de Instrucciones

root@kitploit:~
bool on_instruction(const trace_record_t *rec, void *ctx) {
    printf("0x%08x: 0x%08x\n", rec->pc, rec->instruction);
    return true;
}

int traced = rp2350_trace(target, 0, 100, on_instruction, NULL, false);

Ejecuta paso a paso las instrucciones mediante DCSR.step. ~5ms por instrucción sin captura de registros, ~80ms con captura completa de registros.

Búfer de Programa

Ejecución directa de instrucciones RISC-V en contexto de depuración:

root@kitploit:~
uint32_t progbuf[] = {
    0x34202473,  // csrr s0, mcause
    0x00100073   // ebreak
};
rp2350_execute_progbuf(target, 0, progbuf, 2);
swd_result_t mcause = rp2350_read_reg(target, 0, 8);

El acceso a CSR usa esto internamente, ya que Hazard3 no admite comandos CSR abstractos.

Compilación

root@kitploit:~
add_subdirectory(lib/pico2-swd-riscv)
target_link_libraries(your_app pico2_swd_riscv)

Verbosidad de depuración (en tiempo de compilación):

root@kitploit:~
set(PICO2_SWD_DEBUG_LEVEL 3)  # 0=none, 1=warn, 2=info, 3=debug

Detalles Internos

Protocolo de Cable

SWD usa paquetes de solicitud de 8 bits (start, APnDP, RnW, addr[3:2], paridad, stop, park), ACK de 3 bits (OK=1, WAIT=2, FAULT=4) y fases de datos de 33 bits con paridad. Los ciclos de turnaround gestionan los cambios de dirección de SWDIO. Las respuestas WAIT se reintentan automáticamente (por defecto: 5 reintentos, retroceso de 100us).

Codificación DP_SELECT de RP2350

No estándar: [15:12]=APSEL, [11:8]=0xD, [7:4]=bank, [0]=ctrlsel. El 0xD en los bits[11:8] es obligatorio pero no está documentado.

Activación de DM

Protocolo de enlace de tres fases a través del CSW del Banco 1: desactivar (0x00000000), activar (0x00000001), configuración completa (0x07FFFFC1). Respuesta de estado esperada: 0x04010001.

Acceso a Registros

GPRs mediante comandos abstractos (regno 0x1000+n, transferencia de 32 bits). CSRs mediante el búfer de programa: guardar s0, ejecutar csrr s0, <csr> o csrw <csr>, s0, leer/restaurar s0.

Acceso al Bus del Sistema

SBCS configurado con sbaccess=32bit y sbreadonaddr. Escribir en SBADDRESS0 dispara la lectura del bus; los datos están disponibles inmediatamente en SBDATA0. Las transferencias por bloques habilitan sbautoincrement para lecturas/escrituras en streaming sin configuración de dirección por palabra.

Paso a Paso

Leer DCSR mediante progbuf, establecer el bit de paso (bit 2), reanudar el hart. El hart ejecuta una instrucción y vuelve a entrar en modo de depuración. Limpiar el bit de paso después.

Limitaciones

  • Sin puntos de interrupción por hardware (módulo trigger eliminado, se planea reimplementarlo)
  • Sin SWD multi-drop
  • Sin decodificación de instrucciones comprimidas (lee correctamente, no decodifica nemotécnicos)
  • Sin programación de flash (se puede lograr mediante rp2350_execute_code con un stub)
  • Sin perfilado con precisión de ciclos

Referencias

  • RISC-V External Debug Support v0.13
  • ARM Debug Interface Architecture Specification ADIv5/v6
  • Hoja de datos de RP2350, Capítulo 3.5
  • Manual de Referencia Técnica ARM CoreSight SWD-DP

Licencia

MIT. Consulta LICENSE.

Descargar herramienta