16GB iPod Nano 3G Upgrade
iPod Nano 3세대 저장 공간을 16GB로 늘리기
6년에 걸친 역공학과 펌웨어 패치로 iPod Nano 3세대의 NAND를 16GB SLC 칩으로 교체한 과정을 설명합니다. 8KiB 물리 페이지를 4KiB 논리 블록으로 변환하고, NAND 오류 처리와 부트·디스크 모드까지 손봐 실제 음악 재생과 동기화에 성공합니다.
- 주제
에디터 노트
2020년 4월, 납땜도 역공학도 해본 적 없는 사람이 iPod Nano 3세대의 NAND를 16GB로 바꾸겠다고 나선 기록입니다. 결과만 보면 단순한 용량 업그레이드지만, 이 글의 진짜 재미는 6년에 걸친 디버깅 서사에 있습니다. Red X가 뜨자 펌웨어 속 NAND 허용 목록을 찾아내고, Pwnage 2.0 취약점으로 코드를 실행하고, 진단 모드의 NAND_SPEC 테스트에 4바이트씩 데이터를 밀어 넣어 상태를 빼내는 식의 발상이 계속됩니다. 다만 가장 인상적인 장면은 정작 엉뚱한 데 있습니다. 원인을 찾겠다고 NAND 주변장치의 FMISS라는 코프로세서 명령어 집합을 90%까지 문서화하고 QEMU 에뮬레이션에까지 반영했는데, 알고 보니 그건 문제와 무관했다는 대목입니다. 실제 범인은 납땜이 덜 된 WP# 핀이나, MLC 페이지 쌍 구조 같은 소소한 것들이었습니다. 해커뉴스 댓글의 향수처럼, 이 프로젝트의 목적도 실용성이 아니라 "되게 만드는 것" 자체였습니다. 6년 만에 완성된 약 15GB짜리 iPod이 그 증거입니다.
AI 요약
작성자는 2020년, 납땜이나 역공학 경험이 거의 없는 상태에서 iPod Nano 3세대의 NAND를 더 큰 칩으로 바꾸는 작업을 시작합니다. 외장형 저장 장치를 쓰는 iPod Classic과 달리 Nano는 NAND 칩을 직접 교체해야 합니다. 칩을 바꾼 뒤 기기는 복구 모드조차 진입하지 못하고 ‘Red X’를 표시합니다. 펌웨어가 지원하지 않는 NAND ID를 거부한다고 보고, 부트로더와 펌웨어를 분석해 문제를 하나씩 찾아갑니다.
NAND 초기화와 펌웨어 분석
Rockbox의 NAND 장치 정보 테이블을 단서로 삼아 iPod 펌웨어 안에도 비슷한 테이블이 있음을 확인합니다. BootROM에서 동작하는 Pwnage 2.0 취약점을 이용해 서명되지 않은 코드를 실행하고, EFI 안의 NAND 드라이버가 칩 ID와 구조 정보를 확인하는 흐름을 추적합니다. 초기에는 수정한 EFI를 NOR 플래시에 반복해서 올려야 했습니다. 작성자는 조건 분기에서 기기를 멈추게 하는 방식으로 실행 경로를 좁혔고, 진단 모드가 참조하는 System Information Table에 값을 실어 NAND ID와 상태를 네 바이트씩 읽어내는 방법도 만들었습니다.
칩은 인식됐지만 초기 포맷 단계에서 쓰기 검증이 실패했습니다. 로직 분석기로 NAND 버스를 관찰한 뒤, 칩의 WP# 핀이 패드에 제대로 납땜되지 않았음을 발견했습니다. 이를 고치자 쓰기가 진행됐지만 여섯 번째 페이지부터 데이터가 깨졌습니다. 원인은 MLC NAND의 페이지 쌍 구조였습니다. 이 칩에서는 0번과 6번 페이지가 같은 셀을 나눠 쓰며, 더 좁은 전압 여유를 쓰는 두 번째 비트가 6번 페이지에 놓여 있었습니다. ECC를 손보는 대신 16GB SLC 칩을 골라 포맷에 성공했습니다.
이 과정에서 NAND 주변장치의 FMISS 계층도 분석했습니다. FMISS는 NAND 동작을 처리하는 별도 명령어 집합을 실행하는 코프로세서입니다. 작성자는 데이터시트의 절차와 펌웨어를 대조해 디스어셈블러와 어셈블러를 만들고, 명령어 집합의 약 90%를 문서화했습니다. 이후 다른 개발자와 QEMU 에뮬레이션에도 반영했습니다. 다만 FMISS 분석 자체가 칩 교체를 막던 직접 원인은 아니었습니다.
8KiB 페이지를 4KiB 블록으로 연결
새 NAND의 페이지 크기는 8KiB였습니다. 기존 펌웨어는 4KiB를 기준으로 페이지 변환 비율을 계산하므로 4096을 8192로 나눈 결과가 0이 됩니다. 읽기 요청은 0페이지로 바뀌고, 용량 계산은 0으로 나누기 오류를 일으킵니다. 8KiB 섹터를 그대로 USB SCSI로 보고하면 Linux가 지원하지 않는 섹터 크기라며 장치를 마운트하지도 않습니다.
작성자는 외부에 4KiB 논리 블록을 유지하고 내부에서 8KiB 물리 페이지로 변환하는 방식을 택했습니다. 논리 블록 번호를 2로 나눠 물리 페이지를 찾고, 번호가 짝수면 페이지 앞부분을, 홀수면 뒷부분을 돌려줍니다. 4KiB만 바꾸는 쓰기는 전체 8KiB 페이지를 읽고 일부를 바꾼 뒤 다시 쓰는 read-modify-write로 처리합니다. 작은 임의 쓰기에서 읽기가 추가되고 쓰기 증폭이 커지지만, USB·SCSI 계층과 나머지 펌웨어를 4KiB 기준으로 유지할 수 있습니다.
디스크 모드에는 변환기뿐 아니라 논리 블록 크기와 전체 블록 수를 보고하는 코드도 패치해야 했습니다. 용량은 FTL의 페이지 수를 기준으로 계산하고, 내부 예약 공간을 제외하도록 했습니다. 32,768페이지, 즉 256MiB를 여유 공간으로 남겼습니다. 2,048페이지만 빼면 오류가 다시 나타났고, 2,107페이지까지 실패 범위를 확인한 뒤 넉넉한 값을 채택했습니다. 8KiB 페이지와 더 많은 페이지를 관리하도록 메모리 할당 풀도 키웠습니다.
NAND 구조와 오류 처리 수정
칩은 128페이지 블록 두 개를 두 평면(plane)으로 묶습니다. 펌웨어는 이를 256페이지 블록 하나로 취급해 기록은 두 평면에 모두 하지만 삭제는 한 번만 실행했습니다. 재사용하는 블록의 한쪽 평면에 이전 데이터가 남는 문제가 생겼습니다. 작성자는 평면 비트를 바꿔 삭제 명령을 두 번 실행하도록 수정했습니다.
또 다른 문제는 빈 8KiB 페이지를 읽을 때 ECC가 이를 손상된 데이터로 판정하는 현상이었습니다. 그 결과 불량 블록 검사와 가비지 컬렉터가 정상적인 빈 공간을 불량으로 처리했습니다. 작성자는 빈 페이지에서 반복적으로 나타나는 ECC 결과를 판별해 읽기와 가비지 컬렉션 경로를 각각 수정했습니다. 이 오류는 하드웨어에서 확인했습니다. QEMU의 NAND 모델에는 ECC 오류 상태가 없어 같은 문제를 재현할 수 없었기 때문입니다.
EFI부터 RetailOS까지 패치
NAND 드라이버는 EFI, 디스크 모드, RetailOS 등 여러 펌웨어 이미지에 각각 들어 있습니다. 작성자는 같은 수정 사항을 각 바이너리와 ARM/THUMB 명령어 형식에 맞춰 적용했습니다. EFI에서는 실제 ARMv5TEJ CPU가 지원하지 않는 THUMB-2 NOP를 QEMU가 실행하는 바람에 에뮬레이터와 실기기 결과가 달랐습니다. 올바른 THUMB-1 명령어로 바꾸자 실기기에서 동작했습니다.
RetailOS가 멈춘 원인은 메모리 풀 크기였습니다. 디스크 모드에 맞춰 복사한 풀 크기가 사용자 인터페이스와 NAND 드라이버가 함께 쓰기에는 부족했습니다. 폰트를 불러오다 할당에 실패하면 널 포인터에 기록해 예외 벡터까지 덮어썼습니다. 사용량을 측정해 NAND 쪽 풀을 1.5MiB로 조정하고, 전체 풀은 2MiB로 설정했습니다. 비트맵 할당 실패도 안전하게 처리하도록 고쳤습니다.
마지막으로 배터리 노후화 탓에 NAND 쓰기·삭제 순간 전력이 부족한 문제를 확인했습니다. 또 직접 만든 파티션 테이블이 펌웨어 영역과 데이터 영역을 겹치게 했습니다. 복구 도구가 기기 자체의 재파티션 명령을 실행하도록 바꾸고, 데이터 파티션이 펌웨어 볼륨 다음 블록에서 시작하게 했습니다. About 화면에는 예약 공간을 제외한 약 15GB가 표시됐고, 기기는 재부팅과 음악 동기화 뒤에도 정상적으로 부팅하고 음악을 재생했습니다.
Hacker News 반응
- @Raed667 — iPod Nano 3세대는 제게 특별한 기기입니다. 열네 살쯤 어머니가 생일 선물로 사 주셨고, 지금도 아껴 씁니다. 아마 1년에 한 번 충전할까 말까 하면서 그때 골라 담은 메탈 음악을 듣습니다. 제가 가진 유일한 iPod이자 필요한 전부였어요. 이제 배터리가 거의 충전되지 않지만, 손에 들 때마다 아직 작동하기를 바랍니다.
- @RCitronsBroker — 아, 아버지가 미국 출장에서 하나 사다 주셨습니다. 그걸 정말 자랑스러워했어요.
- @peterburkimsher — NAND 업그레이드 방법을 찾아내신 걸 축하합니다! 저도 Nano 1세대에 다른 플래시 칩을 납땜해 봤지만, 기기가 인식하지 않아 포기했습니다.
- @dmitrygr — 이제야 진짜 Hacker News다운 글이네요! 작성자에게 경의를 표합니다. 잘하셨습니다. NOP 문제는 예상할 만했습니다. QEMU는 실제로 지정한 하드웨어만 엄격히 구현하기보다, 명령어 집합과 기능을 더 넓게 허용하는 경우가 많습니다. NAND는 언제나 괜히 까다롭고요.
- @int32_64 — Apple이 휠을 유지하고 배터리와 저장 공간을 현대화한 iPod 25주년 기념판을 내면 좋겠습니다. Z세대와 예전에 iPod을 썼던 사람들에게 향수를 파는 제품으로 만들면 아주 잘 팔릴 겁니다.
- @KeplerBoy — 최소한 Bluetooth는 들어가야 할 겁니다. 그러면 모뎀이 거의 같은 셈이니 Wi-Fi도 넣을 수 있겠죠. 149달러짜리 Apple Music 기기로 만들고, 기능을 줄인 펌웨어를 얹으면 왜 스트리밍만 지원하는지 설명할 수도 있겠습니다.
- @Marsymars — 참고로 마지막 세대 iPod Nano에는 이미 Bluetooth가 있었습니다.
- @crote — HiBy 같은 회사는 음악 플레이어 제품군을 꽤 잘 꾸리고 있습니다. ‘방해 요소가 적다’는 점을 명시적으로 내세우기도 합니다. 100달러 정도면 꽤 쓸 만한 스마트폰을 살 수 있는데도 피처폰 시장이 여전히 잘 유지됩니다. 그 제품을 사는 사람이 할머니들뿐인 것도 아니고요. 스마트폰은 편리한 기기에서 관심을 빼앗고 사생활을 침해하는 만능 기기로 바뀌었습니다. 많은 사람이 필요악처럼 쓰고, Z세대와 알파세대 중에도 자기 보호를 위해 스마트폰을 거부하는 사람이 점점 늘고 있습니다. 최신 iPod을 찾는 시장이 아주 크지는 않겠지만, Apple Vision이나 Meta의 안경을 찾는 시장보다는 클 수 있다고 봅니다. 수요가 있느냐보다 Apple이 그 수요에 관심을 둘 만큼 큰지, 특히 자사 앱 생태계를 약화시키면서까지 할지가 관건입니다.
원문: Tucker Rosman / 번역·요약: Trawling