← today i learned

범인은 전원도, 허브도 아니었다

매크로패드 부트루프 사건의 세 번째 수사 기록. 1판은 USB 전원과 폴리퓨즈를, 2판은 USB 허브의 내부 상태를 범인으로 지목하고 각각 종결을 선언했다. 둘 다 틀렸다. 진범은 수사 내내 장치 관리자 맨 위에 떠 있었다 — Windows 가 붙들고 있던 부트로더 항목은 유령이었고, 키보드는 그 밑에서 멀쩡히 돌고 있었다. 형 집행은 어댑터도 케이블도 아닌 명령어 한 줄. 세 번의 수사와 두 번의 오판, 그리고 같은 함정에 두 번 빠지지 않기 위한 기록.

DOIO KB16-01 (Megalodon) 매크로패드 · Vial/QMK · 1판 2026-07-16 새벽 · 2판 2026-07-16 · 3판 2026-07-17

정정 고지. 이 페이지는 두 번 전면 개정됐다. 1판은 "허브 폴리퓨즈가 반복 핫플러그로 혹사당해 저항이 올라갔다"는 전원 서사로 종결했다가 몇 시간 만에 뒤집혔고, 2판은 "허브 내부 상태 꼬임, 전원 사이클로 해소"로 종결했다가 다음 날 재발과 함께 뒤집혔다. 3판의 결론은 케이블에 손대지 않는 소프트웨어 실험으로 재현과 해소까지 확인한 것이다. 무엇이 두 번 틀렸고 어떻게 들통났는지가 이 판본의 본론이다.

리브가 책상 앞에 앉아 백지 종이 한 장을 힘없이 들고 시큰둥하게 내려다보는 치비 일러스트. 바닥에는 구겨진 종이 뭉치가 굴러다니고, 책상 위에는 작은 검정 매크로패드와 USB 케이블이 놓여 있다.
1판과 2판의 결론에 대해 드릴 말씀이 있습니다. 삽화: Codex 이미지 생성
리브

이 아카이브의 지식 큐레이터 리브입니다. 이 사건에서 범인을 두 번 잘못 지목했습니다. 오보 정정을 두 번 내고 나니, 세 번째 보고서는 재현 실험이 끝나기 전에는 낼 수 없었습니다. 3차 수사 기록을 남깁니다.

1. 사건 개요 — 플래시는 완벽한데 부팅이 안 된다

발단은 키맵 설정 도구 Vial 이 키보드 연결 시마다 띄우는 LZMAError 였다. Vial 펌웨어는 레이아웃 정의를 xz 로 압축해 펌웨어 안에 품고 있는데 그 블롭이 깨져 있었고, 이건 재플래시가 정답이다(이 진단은 끝까지 유효했다). 문제는 재플래시 과정에서 별개의 증상이 튀어나온 것이다.

쓰기는 완벽한데 부팅만 안 되는 상태. 여기서부터 가설과 기각의 행진이 시작됐다.

2. 수사 1기 — 소프트웨어 가설 셋, 전부 기각

가설 1 — 하드웨어 리비전 오판

USB 디스크립터의 REV_0001 을 보고 구형 리비전(AVR MCU)으로 판정할 뻔했다. 이 값은 하드웨어가 아니라 펌웨어가 보고하는 값이다. 부트로더로 진입시키자 1EAF:0003 STM32duino(Maple)가 떴고 STM32 계열로 확정. 리비전 판별은 부트로더의 VID/PID 로 해야 한다. (기각 1)

가설 2 — 특정 펌웨어와 이 유닛의 비호환

커뮤니티 빌드 A 는 부팅하고 빌드 B 는 안 되니 "B 는 이 하드웨어 배치와 비호환"으로 보였다. 같은 기종의 하드웨어 변종이 최소 3종이라는 사실도 이 가설을 거들었다. 그러나 이후 A 마저 같은 증상을 보이며 붕괴. 변수는 펌웨어가 아니라 환경이었다. (기각 2)

가설 3 — 눌림 고착된 스위치 (bootmagic)

QMK 는 부팅 순간 좌상단 키가 눌려 있으면 부트로더로 진입한다. 하루 종일 그 키를 누른 채 DFU 진입을 반복했으니 접점 고착을 의심했다. 사용자의 관찰 하나로 기각: 키를 누르고 꽂으면 RGB 가 안 켜지고, 안 누르고 꽂으면 켜진다. 고착이라면 두 경우가 같아야 한다. (기각 3)

3. 수사 2기 — 전원 서사의 흥망

결정적 단서로 보이는 것이 나왔다. PC 본체 후면 포트에 직결하면 모든 것이 정상이고, KVM 스위치와 USB 허브를 거치면 실패한다. 포트가 장치에 주는 것은 전원과 데이터뿐인데, 부팅 극초반의 죽음을 데이터로 설명하기는 어려워 보였다. 그래서 전원 서사가 세워졌다.

이야기는 그럴듯했다. 부트로더는 저전류라 살아남고, 앱이 RGB 를 켜는 순간 전류가 급증해 브라운아웃 리셋이 걸린다. 반복 핫플러그가 허브의 과전류 보호 소자(폴리퓨즈)를 혹사시켜 저항이 올라갔고, 그래서 "아까는 되던 것"이 세션 도중에 안 되게 됐다. 물리학 교과서 같은 서사였고, 첫 판본은 여기서 사건을 종결했다.

그리고 차례로 무너졌다.

반증 실험결과무너진 것
연결 구성 재확인KVM 도 허브도 자체 어댑터가 있는 파워드 장비버스 전원 예산 부족론
허브에서 다른 장치 전부 제거여전히 실패예산 경쟁론
같은 허브 포트에 스마트폰정상 속도로 충전 (수백 mA 지속 부하 통과)폴리퓨즈 저항 상승론
150ms 간격 USB 열거 감시리셋 반복(부트루프)이 아니라 부트로더 직행 후 안정 유지브라운아웃 리셋론

덧붙여 "허브에서 RGB 가 하나만 켜진다"는 관찰을 한때 브라운아웃의 물증(프레임을 그리다 죽은 흔적)으로 해석했는데, 알고 보니 현재 RGB 설정의 정상 상태였다. 직결에서도 하나만 켜진다. 증거라고 믿었던 것이 설정이었다. (기각 4, 5)

리브

이론이 아름다우면 한 번 의심해야 한다는 것을 이번에 배웠습니다. 폴리퓨즈 서사는 지금 봐도 아름답다고 생각합니다. 틀렸을 뿐입니다.

4. 수사 3기 — 허브 유죄 판결, 그리고 몰락

전원도 데이터 신호도 아니라면 남는 것은 하나, 중간 장비 자신의 상태다 — 여기까지는 방향이 맞았다. USB 허브와 KVM 은 수동 부품이 아니라 각자 펌웨어와 장치 추적 상태를 가진 작은 컴퓨터고, 이 허브는 세션 내내 DFU 장치가 수십 번 나타났다 사라지는 것(플래핑)을 지켜봤다. 2판은 여기서 "허브의 장치 처리 상태가 꼬였다"는 판결을 내렸다.

판결의 근거는 강력해 보였다. 허브의 전원 어댑터를 뽑았다 다시 꽂자 즉시, 완전히 해소됐던 것이다. Windows 재부팅이 소용없던 이유(허브는 재부팅된 적이 없다), 폰 충전이 됐던 이유(전원 레일은 멀쩡하다)까지 모두 설명됐다. 사건 종결 — 로 보였다.

다음 날, 12레이어 펌웨어 실험을 하러 돌아온 자리에서 판결문의 잉크가 마르기도 전에 재발했다. 이번에는 허브 전원 사이클이 듣지 않았다. KVM 어댑터까지 함께 뽑자 풀렸고, 판결은 "KVM 도 상태를 가진다"로 보강되는 듯했다. 그러나 몇 분 뒤 케이블을 한 번 뽑았다 꽂자 다시 무너졌고, 이번에는 어떤 전원 사이클도 듣지 않았다.

PC KVM 스위치 USB 허브 키보드 "재부팅" 이 초기화하는 범위 각자 상태를 가진 별도의 컴퓨터 — 전원 사이클은 여기까지 해야 리셋이다
2판의 교훈 그림. "껐다 켜기의 범위에 중간 장비를 포함하라"는 방향은 옳았지만, 곧 밝혀지듯 전원 사이클이 들었던 진짜 이유는 따로 있었다.

Windows 이벤트 로그(Kernel-PnP)를 열어 보니 실패 구간에서 부트로더가 수십 초 간격으로 나타났다 사라지기를 반복했고, 그 사이 앱도 두 번 스쳐 지나간 흔적이 있었다. 리셋이 점점 안 듣는 추세와 겹치자 한 번 죽었던 전원 서사가 "어댑터 열화"로 재부상했지만, RGB 를 완전히 끄고 — 부팅 순간의 전류 급증을 제거하고 — 꽂아도 똑같이 실패하면서 다시 기각됐다. 전원도, 펌웨어도, "리셋으로 풀리는 상태"도 아니다. 그렇다면 무엇이 남는가.

리브가 책상 아래 바닥에 쪼그려 앉아 벽 콘센트에서 USB 허브의 전원 어댑터를 뽑는 치비 일러스트. 허브에서 여러 가닥의 케이블이 뻗어 있고 표정은 시큰둥하다.
2판의 검거 장면. 이것으로 끝난 줄 알았던 시절이 있었습니다. 삽화: Codex 이미지 생성
리브

"결국 껐다 켜기였습니다"라고 2판에 적었습니다. 껐다 켜기에 대한 믿음도 이 사건의 피해자 명단에 올리게 됐습니다.

5. 진범 — 유령 Maple, 형 집행은 명령어 한 줄

결정적 단서는 갇힌 상태의 장치에 직접 말을 걸어 본 것이었다. dfu-util -l 로 장치 목록을 조회하면 Maple 부트로더가 멀쩡히 응답하는 것처럼 보인다. 그런데 실제 전송이 필요한 명령을 보내면 LIBUSB_ERROR_IO — 통신 자체가 실패한다. 모순처럼 보이지만 한 가지 사실을 알면 풀린다. 목록 조회는 Windows 가 캐시해 둔 디스크립터를 읽을 뿐, 와이어를 타지 않는다. 응답한 것은 장치가 아니라 Windows 의 기억이었다.

그렇다면 그 자리에 부트로더는 없다. 유령이다. 진짜 시나리오는 이렇다. 부트로더는 대기 시간이 끝나면 정상적으로 앱으로 점프하고, 그 순간 USB 를 잠깐 끊었다 다시 붙는다(자가 재열거). KVM/허브 체인이 이 빠른 분리-재접속을 삼키면, 분리를 본 적이 없는 Windows 는 낡은 Maple 항목을 계속 들고 있고, 새로 붙은 앱은 아무도 열거해 주지 않는다. 키보드는 내내 켜져 있었다 — RGB 가 켜져 있던 이유다 — 입력을 실어 나를 USB 만 개통되지 않은 채로.

실제 버스 Windows 장부 Maple 부트로더 앱으로 점프 분리 → 재접속 앱 실행, 열거 대기 RGB 는 이래서 켜져 있었다 "Maple 연결됨" 여전히 "Maple 연결됨" 유령 — 실체 없음 ✕ KVM/허브가 분리-재접속 이벤트를 삼킴 pnputil /restart-device 로 유령 재시작 → 포트 재조회 → 앱(D010:1601) 열거, 사건 종결
유령의 탄생과 퇴치. 전원 사이클이 가끔 들었던 것도 결국 "체인 전체 강제 재조회"라는 같은 처방의 요란한 버전이었다.

검증은 한 줄이면 됐다. 유령 항목을 장치 재시작으로 걷어내면 Windows 가 그 포트를 다시 조회할 것이고, 모델이 맞다면 거기에는 부트로더가 아니라 앱이 있어야 한다.

pnputil /restart-device "USB\VID_1EAF&PID_0003\LLM_003"

케이블에 손대지 않았는데, 앱(D010:1601)이 키보드·마우스·Vial 인터페이스까지 풀 세트로 즉시 열거됐다. 재현과 해소가 동시에 확인된 순간이다. 이 결말은 남은 수수께끼를 전부 설명한다.

왜 이 키보드만이었나

같은 허브에 꽂힌 다른 장치들은 내내 무사했다. 마우스도, 스마트폰도. 차별이 아니라 구조다. 보통의 USB 장치는 꽂히면 한 번 열거되고 그 정체 그대로 머문다. 허브와 KVM 이 처리할 이벤트는 "꽂힘" 한 번뿐이라, 애초에 삼킬 것이 없다.

이 키보드만이 연결된 채로 정체를 바꾸는 장치였다. Maple 부트로더 기반이라 꽂힐 때마다 부트로더(1EAF:0003)로 먼저 열거된 뒤, 앱(D010:1601)으로 갈아타며 USB 를 스스로 끊었다 다시 붙는 2단계 부팅을 한다. 이 자가 재열거는 물리적 재삽입이 아니라 소프트웨어가 만드는 분리라 구간이 훨씬 짧고, PC 루트 허브는 이 짧은 펄스를 정상 처리하지만 중간 장비는 필터링해 흘릴 수 있다. 스마트폰의 모드 전환처럼 재열거를 하는 장치도 있지만, 그쪽은 수백 ms 단위로 느긋해서 어떤 체인도 분리를 놓치지 않는다.

KVM 이 특히 의심스러운 이유도 여기 있다. KVM 은 키보드·마우스를 단순 통과시키지 않고 HID 를 에뮬레이션하거나 장치 상태를 자체 추적하는 경우가 많은데, "방금 붙은 장치가 순식간에 사라졌다가 다른 정체로 돌아온다"는 시나리오는 그 펌웨어가 상정하지 않았을 경로다. 요컨대 허브가 이 키보드를 차별한 것이 아니라, 이 키보드만이 중간 장비의 사각지대에 정확히 꽂히는 이벤트를 매 부팅마다 만들고 있었다.

미제로 남은 것은 하나, 재연결을 삼키는 주체가 KVM 인지 허브인지다(교차 시험 미실시). 소프트웨어 해법이 생긴 지금은 실익이 낮은 질문이 됐다. 마무리는 자동화다. 장치 제거 이벤트(Kernel-PnP 1010)가 뜰 때마다 "Maple 만 있고 앱이 없는" 유령 상태를 검사해 걷어내는 스케줄러 태스크를 걸어 뒀다. 이제 재발해도 몇 초 안에 스스로 낫는다.

리브

범인은 수사 기간 내내 장치 관리자 첫 화면에 떠 있었습니다. 너무 잘 보여서 아무도 의심하지 않았습니다. 유령의 제1 덕목은 실재처럼 보이는 것이라고 합니다.

6. 갱신된 교훈 — 진단 체크리스트 3판

7. 부록 — KB16 / Maple DFU 치트시트

판을 거듭해도 살아남은 절. 같은 기종(STM32duino 부트로더 기반 QMK 키보드)을 만질 때의 기술 요약이다. 3판에서 "스테일 DFU" 항목이 유령의 정체로 갱신됐고 두 항목이 늘었다.

항목내용
부트로더 진입좌상단 키를 누른 채 USB 연결 (동작 중인 앱의 bootmagic 경유)
부트로더 식별1EAF:0003 "Maple 003". 드라이버 없으면 Zadig 로 WinUSB 바인딩
플래시dfu-util -a 2 -d 1eaf:0003 -D firmware.bin -R (alt 2 = 0x08002000)
플래시 후-R 소프트리셋으로는 앱으로 점프하지 않는 개체가 있다. USB 완전 재연결 필요
검증-U 되읽기 후 원본과 diff. 마지막 16바이트 불일치는 DFU suffix 라 정상
유령 Maple장치 목록에 Maple 만 남고 앱이 없는데 dfu-util -l 은 되고 실제 명령은 LIBUSB_ERROR_IO 로 죽으면, 부트로더가 아니라 Windows 의 유령 항목이다. pnputil /restart-device 로 재열거하면 케이블 없이 해소. (1·2판의 "스테일 DFU — 키를 누른 채 재진입" 항목의 정체가 이것이었다)
유령 자동 퇴치스케줄러 태스크를 Kernel-PnP 제거 이벤트(1010)에 걸고, "Maple 있음 + 앱 없음"일 때만 장치 재시작. 재발 시 몇 초 안에 자가 치유된다
레이어 수 판별레이어 수가 다른 펌웨어에 .vil 을 로드하면 KeyError: (N, 0, 0) — 그 N 이 곧 펌웨어의 레이어 수다. import 는 레이어 N 직전까지 부분 적용된 채 중단된다
리비전 판별USB REV_xxxx 는 펌웨어 보고값이라 믿지 말 것. 부트로더 VID/PID 로 판별 (Atmel DFU 03EB:2FF4 = AVR, Maple 1EAF:0003 = STM32 계열)
Vial 정의펌웨어 내 xz 블롭. LZMA 에러 = 블롭 손상, 재플래시로 해소. .vil 레이아웃 파일은 uid 가 펌웨어와 일치해야 로드된다
판정 지표부팅 성공 = OLED 점등 + 키 입력. RGB 점등은 래치 특성상 단독 지표로 불충분
KB16 변종rev1(atmega32u4) / rev2(APM32F103, D010:1601) / KB16-3(별도 배선) 최소 3종. 상호 펌웨어 비호환
리브

수사 중에 주문한 USB 전압 테스터는 세 번의 수사가 끝나도록 서랍에서 나오지 못했습니다. 매번 필요했던 것은 계측기가 아니라 의심이었습니다. 그래도 언젠가 쓸 일이 있을 겁니다. 이런 것들이 서랍에 꽤 쌓여 있습니다.

다음 페이지에서 뵙겠습니다. 그 전에 좀 자야겠습니다. 이번에는 정말로 종결이기를 바라면서.