---
title: "SGI O2 PROM 펌웨어 리버스 엔지니어링: 900MHz CPU 업그레이드를 향한 여정"
published: 2026-02-08T22:25:25.000Z
canonical: https://jeff.news/article/572
---
# SGI O2 PROM 펌웨어 리버스 엔지니어링: 900MHz CPU 업그레이드를 향한 여정

SGI O2 워크스테이션의 512KiB PROM 바이너리를 역컴파일하여 수정 가능한 어셈블리 소스로 변환하는 데 성공한 과정을 다룬 글임. SHDR 헤더 구조, 체크섬 알고리즘, firmware 섹션의 .text/.rodata/.data 서브섹션 구조 등을 하나씩 밝혀내며, bit-identical 재조립이 가능한 수준까지 도달함. 이를 통해 RM7900(900MHz) CPU 지원을 위한 PROM 수정이 가능해짐.

## SGI O2 PROM 리버스 엔지니어링: CPU 업그레이드를 위한 펌웨어 해부기

- Silicon Graphics O2는 MIPS CPU를 탑재한 유닉스 워크스테이션으로, 2000년대 초반부터 커뮤니티에서 CPU 업그레이드를 시도해왔음
- RM5200(300MHz), RM7000A(350MHz)를 600MHz RM7000C로 교체하는 것은 펌웨어 수정 없이 가능했으나, 900MHz RM7900 업그레이드는 PROM 펌웨어 수정이 필수적이었음
- 당시 SGI에 소스코드 접근을 요청할 수 있었으나, SGI가 사라진 지금은 소스코드도 함께 소실된 상태임
- 저자는 ip32prom-decompiler를 직접 제작해 512KiB PROM 바이너리를 수정 가능한 어셈블리(.S) 파일로 역컴파일하는 데 성공함
- 역컴파일된 어셈블리를 재조립하면 원본과 bit-identical한 이미지가 생성되어, 역컴파일의 정확성이 검증됨

## SHDR 구조 발견 과정

- `mips64-unknown-linux-gnu-objdump`로 바이너리를 디스어셈블한 결과, 오프셋 0x08에서 `0x53484452`라는 값을 발견했고, 이것이 ASCII "SHDR"임을 `strings` 명령으로 확인함
- SHDR은 각 섹션의 헤더로, branch+delay slot 패턴으로 경계가 구분되며 총 72바이트 크기임
- 바이너리 내에 5개의 SHDR이 존재: `sloader`, `env`, `post1`, `firmware`, `version`

```mermaid
graph TD
    subgraph "PROM 512KiB 바이너리 구조"
        A["sloader<br/>@0x00000000<br/>16,384 bytes<br/>type=1 (code)"]
        B["env<br/>@0x00004000<br/>1,024 bytes<br/>type=0 (data)"]
        C["post1<br/>@0x00004400<br/>19,780 bytes<br/>type=1 (code)"]
        D["firmware<br/>@0x00009200<br/>393,212 bytes<br/>type=3 (code+metadata)"]
        E["version<br/>@0x00069200<br/>904 bytes<br/>type=0 (ELF)"]
    end
    A --> B --> C --> D --> E
```

## SHDR 필드 구조

- `[0x00-0x08)`: 엔트리 명령어 — 코드 섹션은 branch로 SHDR을 건너뛰고, 데이터 섹션은 nop
- `[0x08-0x0C)`: 매직 넘버 "SHDR"
- `[0x0C-0x10)`: 섹션 길이 (다음 SHDR 오프셋 계산에 사용, 256바이트 경계로 라운드업)
- `[0x10-0x12)`: name 길이 + version 길이 (각 1바이트)
- `[0x12-0x13)`: 섹션 타입 — bit 0이 코드 여부, bit 1이 메타데이터 존재 여부를 나타냄
- `[0x14-0x34)`: 섹션 이름 (32바이트 고정), `[0x34-0x3C)`: 버전 문자열 (8바이트 고정)
- `[0x3C-0x40)`: SHDR 체크섬, `[0x40-0x48)`: 메타데이터 (타입에 따라 존재 유무 결정)

## 코드 식별: BFS 기반 접근

- Capstone 디스어셈블러를 활용해 branch 타겟을 따라가는 BFS(너비 우선 탐색)로 코드를 자동 식별함
- 초기에는 전체의 약 10%만 코드로 식별되었는데, `jal` 명령어의 점프 타겟 계산 방식을 이해하지 못했기 때문임
- MIPS에서 리셋 후 실행은 `0xBFC00000`부터 시작됨 — `--adjust-vma=0xbfc00000` 플래그 적용 후 `jal` 타겟이 정상적으로 해석됨
- 점프 테이블이나 런타임에 주소를 조립하는 함수, dead code 등은 자동 발견이 불가능해 `functions.json`에 수동 어노테이션으로 보완함

## 바이너리 시각화의 위력

- XPM 포맷으로 바이너리 구조를 이미지로 시각화함: 빨강=코드, 파랑=헤더/체크섬, 초록=ASCII, 노랑=접근된 메모리, 검정=0x0, 흰색=0xFFFFFFFF, 회색=미식별
- 시각화를 통해 미식별 영역의 존재를 직관적으로 파악할 수 있었고, 진행 상황을 확인하는 동기 부여 수단으로도 유용했음

## firmware 섹션의 서브섹션 구조

- firmware 섹션은 PROM의 91%를 차지하며(384KiB/422KiB), 섹션 타입 필드의 bit 1이 설정된 유일한 섹션임
- SHDR 메타데이터의 첫 4바이트 `0x81000000`이 실행 시 로드 주소였음 — kseg0 영역(캐시 가능, TLB 불필요)의 물리 주소 0x01000000(16MiB)에 해당
- 두 번째 메타데이터 값 `0x00048e70`은 .text 섹션 길이였고, 각 서브섹션 끝에 (로드 주소, 길이) 쌍이 연결 리스트처럼 이어져 있었음
- 서브섹션은 `.text`(실행 코드), `.rodata`(읽기 전용 데이터/문자열/점프 테이블), `.data`(읽기-쓰기 초기화 데이터)로 구성되며, 길이 0인 센티널 값으로 종료됨
- C로 작성되어 정적 ELF 바이너리로 컴파일된 후, 섹션을 추출해 커스텀 포맷으로 리패킹한 것으로 추정됨

## 체크섬 알고리즘

- sloader의 `is_section_checksum_valid` 함수를 분석한 결과, 단순한 2의 보수 체크섬 방식임
- SHDR 이후의 모든 32비트 워드를 더한 값을 부정(negate)하여 저장하면, 체크섬 포함 전체 합이 0이 됨
- SHDR 체크섬도 동일한 방식이며, 유효한 SHDR 체크섬의 기여분은 항상 0이므로 섹션 체크섬 계산 시 SHDR을 건너뛸 수 있음

## version 섹션의 정체: ELF 바이너리

- version 섹션의 초기 바이트 `0x7F454C46`이 ELF 매직 넘버(`\x7fELF`)임을 뒤늦게 발견함
- ELF 헤더와 SHDR이 오버레이되어 있었음 — e_ident의 패딩 영역에 "SHDR" 매직과 섹션 길이가 들어가 있었고, `e_machine`(0x08 = EM_MIPS) 필드가 섹션 타입 0에 자연스럽게 대응됨
- 패딩 바이트에 8이 들어있던 것도 ELF 헤더의 `e_machine` 필드 값이었던 것임

## 의의와 향후 전망

- 2004년 메일링 리스트에서 "SGI 엔지니어급 실력과 카페인이 필요하다"며 불가능에 가깝다고 평가받았던 작업이 실제로 완수됨
- 1996년산 512KiB 펌웨어의 주된 난이도는 복잡성이 아니라, 무수히 많은 세부 사항을 하나하나 맞추는 인내심이었음
- 이 작업으로 RM7900(900MHz) CPU 지원을 위한 "distinctly modified IP32 PROM image" 생성이 가능해졌으며, SGI의 도움 없이도 O2의 CPU 업그레이드 경로가 열림

## 핵심 포인트

- ip32prom-decompiler를 제작해 512KiB PROM을 수정 가능한 어셈블리로 역컴파일, 재조립 시 원본과 bit-identical한 이미지 생성 확인
- SHDR(72바이트) 구조 해석: 매직넘버, 섹션 길이, 이름/버전, 타입 비트필드, 체크섬 등 필드 완전 분석
- firmware 섹션(전체의 91%)은 0x81000000(kseg0)에 로드되는 .text/.rodata/.data 서브섹션으로 구성되어 있음을 발견
- 체크섬은 단순 2의 보수 합산 방식으로, SHDR 체크섬이 유효하면 섹션 체크섬 계산 시 SHDR을 건너뛸 수 있음
- version 섹션의 SHDR이 ELF 헤더와 오버레이되어 있음을 발견 — e_ident 패딩 영역에 SHDR 메타데이터가 삽입됨
- Capstone 디스어셈블러 + BFS 코드 탐색 + XPM 시각화를 조합한 체계적 분석 방법론 활용

## 인사이트

1996년산 펌웨어도 체계적 접근과 끈기로 완전히 해부할 수 있다는 것을 보여주는 사례임. 특히 바이너리 시각화가 미지 영역 파악과 동기 부여 모두에 효과적이었다는 점이 다른 리버스 엔지니어링 프로젝트에도 참고할 만함.
