Skip to content
KitploitKITPLOIT
도구블로그
Log in
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
pico2-swd-riscv — RP2350 RISC-V 코어용 SWD 디버그 프로브 라이브러리입니다. PIO 비트 뱅잉을 통해 두 개의 GPIO 와이어로 중단/재개/단계 실행, 레지스터 및 메모리 접근, 코드 실행, 명령어 추적을 제공합니다. | Kitploit
도구/GitHubGitHub/jackdoe/pico2-swd-riscv
Embedded Systems SecurityReverse EngineeringDebuggersHardware HackingHardware SecurityFirmware Analysis
GitHubjackdoe/pico2-swd-riscv

pico2-swd-riscv

RP2350 RISC-V 코어용 SWD 디버그 프로브 라이브러리입니다. PIO 비트 뱅잉을 통해 두 개의 GPIO 와이어로 중단/재개/단계 실행, 레지스터 및 메모리 접근, 코드 실행, 명령어 추적을 제공합니다.

저장소 보기
853177개월 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

pico2-swd-riscv

RP2350 RISC-V (Hazard3) 코어용 SWD 디버그 프로브. 하나의 Pico2가 두 개의 GPIO 와이어를 통해 다른 Pico2를 디버깅합니다.

0. 바이브 코드 경고 (사람이 작성함)

코드의 약 80%는 바이브 코딩되었습니다. README는 거의 완전히 생성되었습니다(이 바이브 코드 경고 섹션 제외). 오실로스코프와 문서를 보며 많은 밤을 보냈고, sba/read/write 레지스터, 추상 명령어, progbuf를 할 수 있는 작동하는 프로토타입을 만들었습니다. 나머지는 Claude Code로 완료했습니다. 테스트는 꽤 포괄적인 테스트 스위트이며, 저는 이 라이브러리의 핵심을 제 프로젝트에서 사용하지만, 흔히 말하듯 "hic sunt dracones"(여기 용이 있다)입니다. 또한 README를 읽고 코드에서 잘못된 점을 발견하지 못했으며(잘못되거나 불명확한 부분은 제거했습니다).

이 프로젝트는 제가 100% 이해하지 못하고, 명백히 "사용할 수 있는" 기존 코드가 없는 더 복잡한 프로젝트를 바이브 코딩하는 사례 연구였습니다. 약 1000줄의 코드로 시작했으며, 제가 직접 작성하고 잘 알고 있었고, rp2350, arm swd, riscv 디버그 문서를 읽고, 오실로스코프와 openocd로 데이터를 캡처한 다음 디코딩하여 웨이크업 시퀀스와 읽기/쓰기 명령어를 분석했습니다. 작동하게 만든 후 Claude에게 주어 다른 프로젝트에서 사용할 수 있는 라이브러리로 만들게 했고, 그 후 천천히 구축해 나갔습니다.

약 3~4천 줄의 코드 이후에는 무슨 일이 일어나고 있는지 완전히 감을 잃었고, 이 코드를 제가 작성했다고 생각하지 않지만, 테스트를 계속 추가하는 것이 "좋게" 느껴졌거나 적어도 안심이 되었습니다.

약간의 가스라이팅이 있었는데, 특히 dap_read_mem32가 MEM-AP TAR/DRW/RDBUFF 프로토콜이 아닌 RAM에서 읽는 것이라고 오해하여 엄청난 양의 넌센스가 발생했습니다.

전반적으로 끔찍한 경험이었다고 말하고 싶습니다. 거의 10,000줄의 코드를 작성하는 데 10시간이 걸렸지만, 이 프로젝트를 제 프로젝트로 생각하지 않으며, 성취감이나 성장감도 없습니다.

반대로, AI를 사용하여 모든 문서(수천 페이지)를 읽고, 오실로스코프 데이터를 디코딩하는 유용한 스크립트를 작성하고, 문서에서 압축된 C 구조체를 만드는 등의 작업은 매우 좋았고, 그 후에는 기분이 좋았습니다. 첫 번째 레지스터를 읽고 SBA를 통해 메모리를 읽을 수 있었을 때는 정말 기분이 좋았습니다.

주요 문제는 '취향'입니다. 제가 코드를 작성할 때는 좋은지 나쁜지 느낌이 옵니다. 작성하는 동안 잘못된 것을 알지만, Claude Code를 사용하면 매우 빨리 무감각해져서 구분할 수 없게 됩니다. "읽기"는 괜찮지만, 느낌이 어떤지 모르겠습니다. 이 경우 코드가 약 4배(1k에서 4k 라인)로 늘어났을 때 발생했습니다. 더 나쁜 것은, 코드에 대한 제 정신 모델이 완전히 사라졌고, 그와 함께 소유권도 사라졌습니다.

토큰에는 이유나 목적이 없습니다. 그래서 코드를 읽는 것이 엄청나게 어렵습니다. 각 토큰이 완전히 넌센스일 수 있기 때문입니다. 사람이 작성한 코드를 읽을 때는 기호에 목적이 있습니다. 누군가 "이걸 변수에 넣고, 나중에 상태를 확인해야지"라고 생각한 것입니다. 그래서 나는 그 사람인 척하고, 왜 이것을 작성했을까? 하고 생각합니다. 곧 이해하게 됩니다. 그들은 인간이고 나도 인간이기 때문입니다. 하지만 AI 기호에는 이유가 없고, 더 나쁜 것은 모두 기만적으로 정확해 보여서, 잘못된 것인지 10배는 더 열심히 생각해야 합니다. 인간의 코드(자신의 코드 포함)는 얼마나 신뢰할 수 있는지 평가하기가 꽤 쉽고, 일관성이 있습니다. AI 코드에서는 한 함수가 당신이 작성했을 것보다 훨씬 나을 수 있고, 두 줄 아래의 코드는 엄청나게 좋아 보이지만 구조적으로 잘못된 카고 컬트 쓰레기일 수 있습니다.

결국 저는 와이어, 타이밍, 하위 레벨 AP/DP 메커니즘, SBA, progbuf에 대한 좋은 이해를 얻었다고 말할 수 있지만, 전체를 직접 작성하지 않은 것을 후회합니다. 10배의 시간이 걸렸더라도 말이죠.

정말 싫어요.

그리고 역겨움과 수치심을 느끼지 않을 수 없습니다. 이것이 지금의 프로그래밍인가요? 이것이 중간 단계이고 더 나은 방향으로 변하기를 진심으로 바랍니다. 문제는 "더 나은 것"이 무엇인지 모른다는 것입니다. 어떤 사람들에게는 코드를 작성하지 않는 것이고, 다른 사람들에게는 문제를 모델링하지 않는 것이며, 또 다른 사람들에게는 생각하지 않아도 되는 것입니다. 제 경우에는 잘 모르겠습니다. 저는 물건을 만들고 싶고, 많은 경우 무언가를 알고 싶지 않지만 사용하고 싶습니다. 예를 들어 rp2350 USB 호스트 컨트롤러에서 인터럽트를 재무장하는 방식과 epx 레지스터가 공유되는 방식은 아마 좋은 이유로 매우 짜증나지만, 저는 그것을 사용하여 제 CBI 드라이버를 만들고 싶을 뿐입니다.

제가 만들고 싶은 것이 무엇인지 질문해야 할 것 같습니다. USB 칩 레지스터에서 CBI, UFI, FAT16, OS까지 스택을 올라갈 수 있기 때문입니다. 하지만 왜 거기서 멈추나요? 회로도, PCB, CAD 파일을 만들고, 공장에 자동으로 보내고, 그냥 저에게 배송합니까? 하지만 왜 거기서 멈추나요? 웹샵을 만들고, 판매를 시작하고, 커뮤니티를 만들고, 광고, 마케팅, 언박싱 비디오를 생성하고, 아마도 바이럴 밈? 주문을 공장에서 직접 처리하고, 주문에 따라, 문제가 있으면 고객 지원이 준비되어 있습니다.

그동안 저는 무엇을 합니까? 해변에 앉아 있나요? 저는 해변을 싫어합니다.

어디서 멈출까요?

추신: 시인이 말했듯이: 당신이 원하는 것을 얻는 대가는 당신이 한때 원했던 것을 얻는 것입니다.

아키텍처

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)

각 레이어는 자체 상태를 유지하며 바로 이웃하고만 통신합니다.

사용법

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);

Hart 제어

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);

두 hart(0과 1)는 독립적으로 제어 가능합니다.

메모리 접근

시스템 버스 접근(System Bus Access)을 통한 비침습적 접근입니다. Hart가 실행 중인 상태에서도 작동합니다.

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);

블록 전송은 성능을 위해 SBA 자동 증가(auto-increment)를 사용합니다.

코드 실행

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);

대상 SRAM에 업로드하고, 검증하고, PC를 설정하고, 실행을 재개합니다.

명령어 추적

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);

DCSR.step을 통해 명령어를 단일 스텝(single-step)합니다. 레지스터 캡처 없이 명령어당 ~5ms, 전체 레지스터 캡처 시 ~80ms.

프로그램 버퍼

디버그 컨텍스트에서 직접 RISC-V 명령어 실행:

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);

CSR 접근은 Hazard3가 추상 CSR 명령어를 지원하지 않으므로 내부적으로 이를 사용합니다.

빌드

add_subdirectory(lib/pico2-swd-riscv)
target_link_libraries(your_app pico2_swd_riscv)

디버그 상세도 (컴파일 타임):

set(PICO2_SWD_DEBUG_LEVEL 3)  # 0=없음, 1=경고, 2=정보, 3=디버그

내부 구조

와이어 프로토콜

SWD는 8비트 요청 패킷(start, APnDP, RnW, addr[3:2], parity, stop, park), 3비트 ACK(OK=1, WAIT=2, FAULT=4) 및 턴어라운드(turnaround) 사이클과 함께 33비트 데이터 단계를 사용합니다. 턴어라운드 사이클은 SWDIO 방향 변경을 처리합니다. WAIT 응답은 자동으로 재시도됩니다(기본값: 재시도 5회, 100us 백오프).

RP2350 DP_SELECT 인코딩

비표준: [15:12]=APSEL, [11:8]=0xD, [7:4]=bank, [0]=ctrlsel. bits[11:8]의 0xD는 필수지만 문서화되지 않았습니다.

DM 활성화

Bank 1 CSW를 통한 3단계 핸드셰이크: 비활성화(0x00000000), 활성화(0x00000001), 전체 구성(0x07FFFFC1). 예상 상태 응답: 0x04010001.

레지스터 접근

GPR은 추상 명령어(regno 0x1000+n, 32비트 전송)를 통해 접근. CSR은 프로그램 버퍼를 통해: s0 저장, csrr s0, <csr> 또는 csrw <csr>, s0 실행, s0 읽기/복원.

시스템 버스 접근

SBCS는 sbaccess=32bit 및 sbreadonaddr로 구성됩니다. SBADDRESS0에 쓰면 버스 읽기가 트리거됩니다. 데이터는 SBDATA0에서 즉시 사용 가능합니다. 블록 전송은 스트리밍 읽기/쓰기를 위해 sbautoincrement를 활성화하여 단어별 주소 설정 없이 수행됩니다.

단일 스텝(Single-Step)

progbuf를 통해 DCSR을 읽고, step 비트(비트 2)를 설정하고, hart를 재개합니다. Hart는 하나의 명령어를 실행하고 디버그 모드로 다시 진입합니다. 이후 step 비트를 지웁니다.

제한 사항

  • 하드웨어 중단점 없음(트리거 모듈 제거됨, 재구현 예정)
  • 멀티드롭 SWD 없음
  • 압축 명령어 디코딩 없음(올바르게 읽지만, 니모닉을 디코딩하지 않음)
  • 플래시 프로그래밍 없음(rp2350_execute_code와 스텁(stub)을 통해 가능)
  • 사이클 정확한 프로파일링 없음

참고 자료

  • RISC-V External Debug Support v0.13
  • ARM Debug Interface Architecture Specification ADIv5/v6
  • RP2350 Datasheet, Chapter 3.5
  • ARM CoreSight SWD-DP Technical Reference Manual

라이선스

MIT. LICENSE를 참조하십시오.

도구 다운로드