본문으로 건너뛰기
CoderRed Blog

Article

BC250 8코어 언락 롬 공개 - 기존 개발을 버리고 PEIM부터 다시 만든 과정

지난 BC250 CPU 8코어 언락 글은 제 보드가 부팅되지 않는 장면에서 끝났습니다. 영구 8코어 언락 바이오스를 직접 만들다가 보드가 벽돌이 됐고, J4004 단자에 CH347을 연결해도 BIOS 칩의 JEDEC 식별자가 잡히지 않았어요.

주문해 둔 부품이 도착한 뒤 열풍기로 기존 칩을 떼어냈습니다. 분리한 칩을 CH347과 SOP8 208mil 어댑터에 직접 연결해도 여전히 인식되지 않았습니다. 이 결과로 기존 BIOS 칩의 물리적 사망이 확정됐어요.

새 W25Q128 칩에는 보관해 둔 16MB 롬을 기록했습니다. 기록 검증을 마친 칩을 보드에 납땜하자 BC250이 다시 부팅됐습니다.

이번 글에서는 복구보다 그다음에 만든 언락 롬을 다룹니다.

보드를 살린 뒤 기존 개발분을 전부 버리고 설계를 처음부터 다시 검토했습니다. 콜드 부팅에서 코어 언락을 자동으로 적용하고, 한 번 재부팅한 뒤 8코어 16스레드로 올라오는 P3.00용 롬을 새로 완성했습니다.

롬과 사용 방법은 아래 저장소에 공개했습니다.

coderredlab/bc250-8core-unlock - BC250 P3.00 8코어 언락 펌웨어

BC250 콜드 부팅에서 PEIM 안전 검사를 거쳐 자동 리셋 후 8코어 16스레드로 부팅하는 언락 롬 구조
BC250 P3.00 8코어 언락 롬
전원을 켜면 PEIM이 코어 마스크와 팩토리 퓨즈를 검사하고, 언락에 성공한 경우에만 자동 리셋을 한 번 거쳐 8코어 16스레드로 부팅합니다.

먼저 언락 롬부터 소개하겠습니다

공개한 BC250-P3.00-8Core.rom은 BC250의 P3.00 바이오스를 기준으로 만든 16MiB 전체 플래시 이미지입니다.

콜드 부팅 흐름은 이렇습니다.

전원 인가
PEIM에서 보드와 코어 상태 검사
0x77 코어 presence를 0xFF로 변경
변경 결과 검증
자동 웜 리셋 1회
8코어 16스레드로 부팅

전원 버튼은 한 번만 누릅니다. 내부에서는 펌웨어가 두 번 부팅됩니다. 첫 부팅에서 코어 상태를 바꾸고 자동 리셋한 뒤, 두 번째 부팅에서 8코어를 열거합니다.

기존 자동 DXE 방식도 같은 두 단계를 거칩니다. 제가 바꾼 부분은 부팅 횟수가 아니라 언락 조건과 실패 처리입니다.

항목공개 롬의 동작
대상 바이오스BC250 P3.00
콜드 부팅언락 검사 후 자동 리셋 1회
정상 결과8코어 16스레드
코어 마스크 검사하위 8비트가 정확히 0x77일 때만 진행
팩토리 퓨즈 검사0x5D25C가 0이 아니면 언락 중단
SMU 대기최대 2,500회로 제한
기록 검증presence가 0xFF로 바뀌었는지 재확인
실패 시자동 리셋 없이 기존 6코어 부팅 계속
웜 리부트이미 언락된 상태를 유지하며 바로 부팅

배포 파일의 SHA-256은 아래 값입니다.

1b7bcaa65e247363ad19e6a1dd3e296ae54b254fdeeeb32c8fb8ac505c86ac17

다운로드한 롬은 플래싱 전에 이 값과 비교합니다.

sha256sum BC250-P3.00-8Core.rom

이 롬은 죽은 코어를 고치는 펌웨어가 아닙니다

BC250은 출고 상태에서 8개 CPU 코어 가운데 6개만 사용합니다. 제 보드는 휘발성 언락으로 8코어 16스레드를 며칠간 사용했고, 새로 열린 코어와 전체 16개 스레드의 연산 검증도 통과했습니다.

개체마다 결과는 다를 수 있습니다. 비활성 코어가 실제 불량인 BC250은 코어를 강제로 켰을 때 부팅 실패, 계산 오류, MCE가 발생할 수 있습니다.

롬에는 두 가지 조건을 넣었습니다.

  1. 코어 presence 마스크가 일반적인 제한 상태인 0x77과 정확히 일치해야 합니다.
  2. 팩토리 core-disable 퓨즈 레지스터 0x5D25C가 0이어야 합니다.

조건이 다르면 PEIM은 0xFF를 기록하지 않고 기존 부팅 흐름으로 돌아갑니다.

플래싱 전에는 공개된 휘발성 언락 도구로 해당 보드의 추가 코어를 먼저 확인합니다.

이 롬은 휘발성 방식으로 8코어 16스레드 부팅과 부하 검증을 통과한 보드를 대상으로 합니다. 휘발성 언락에서 부팅이 멈추거나 계산 오류가 발생한 보드는 순정 6코어 상태로 사용합니다.

플래싱 전에 준비할 것들

지원 범위는 P3.00입니다. 다른 BIOS 버전은 현재 테스트하지 않았습니다.

플래싱 전 준비물:

  • 현재 보드에서 직접 읽은 16MiB BIOS 백업
  • 백업 파일을 두 번 읽어 비교한 해시
  • P3.00에서 안정적인 8코어 휘발성 언락 결과
  • 기록 중 전원이 끊기지 않는 환경
  • 실패 시 사용할 외부 SPI 프로그래머와 복구 수단

제 경우에는 CH347, SOP8 208mil 어댑터, 새 W25Q128 칩으로 실제 복구했습니다. 외부 프로그래머가 있어도 인서킷 상태에서 칩이 잡히지 않을 수 있습니다. 제 기존 칩은 보드에서 떼어낸 뒤에도 JEDEC 응답이 없어서 새 칩 교체까지 진행했습니다.

Linux에서 내부 플래싱하는 방법

저장소를 내려받습니다.

git clone https://github.com/coderredlab/bc250-8core-unlock.git
cd bc250-8core-unlock

먼저 현재 BIOS를 백업합니다. 이 파일이 해당 보드의 NVRAM과 설정을 포함한 가장 확실한 롤백 이미지입니다.

sudo flashrom -p internal -r my-stock-backup.rom

백업을 한 번 더 읽고 해시가 같은지 확인하면 읽기 안정성도 확인할 수 있습니다.

sudo flashrom -p internal -r my-stock-backup-2.rom
sha256sum my-stock-backup.rom my-stock-backup-2.rom

두 값이 같으면 공개 롬의 해시를 확인한 뒤 기록합니다.

sha256sum BC250-P3.00-8Core.rom
sudo flashrom -p internal -w BC250-P3.00-8Core.rom

기록 명령의 자체 검증이 끝나도 독립 리드백을 한 번 더 수행합니다.

sudo flashrom -p internal -r verify.rom
sha256sum verify.rom

verify.rom의 SHA-256이 배포 롬의 전체 해시와 같아야 합니다.

1b7bcaa65e247363ad19e6a1dd3e296ae54b254fdeeeb32c8fb8ac505c86ac17

이 보드에서는 flashrom -p internal의 읽기, 쓰기, 자체 검증, 독립 리드백을 모두 확인했습니다.

부팅 뒤에는 이렇게 확인합니다

콜드 부팅에서는 전원을 켠 뒤 몇 초 안에 자동으로 한 번 재부팅됩니다. 그다음 리눅스가 올라오면 논리 CPU 수를 확인합니다.

nproc
grep -c '^processor' /proc/cpuinfo

정상 결과는 둘 다 16입니다.

커널의 하드웨어 오류도 함께 확인합니다.

sudo dmesg -T | grep -iE 'mce|machine check|hardware error|edac'

짧은 부하 검증은 stress-ng로 시작할 수 있습니다.

sudo apt update
sudo apt install -y stress-ng
sudo stress-ng --cpu 16 --cpu-method all --verify --timeout 30m --metrics-brief

부팅 성공과 코어 안정성은 별개입니다. 실제 사용 전에는 새 코어를 포함한 전체 스레드에 부하를 걸고 MCE 로그를 확인합니다.

왜 기존 개발분을 전부 버렸나요?

앞선 글에서 저는 공개된 파이썬 스크립트의 동작을 BIOS 부팅 과정에 넣으려 했습니다. 여러 후보 롬을 만들고 플래싱하던 중 BC250이 부팅되지 않았고, 결국 기존 BIOS 칩의 JEDEC 응답까지 사라졌습니다.

새 칩으로 보드를 복구한 뒤에도 기존 빌더로 만든 후보 하나를 시험했습니다. 시뮬레이션 276회와 안전 검사 46개, 독립 검토까지 통과한 롬이었어요.

그런데 실보드에서는 첫 화면도 나오기 전에 멈췄습니다.

“검사 결과가 모두 통과했는데 실제 보드는 왜 멈췄지?”

원인은 기존 패치의 조기 PCD 접근이었습니다. CCX 초기화에서 PCD 값을 준비되기 전에 요청했고, PEI 초기화 순서가 깨지면서 화면 출력 전 단계에서 멈췄습니다.

시뮬레이터는 제가 모델링한 계약 안에서만 정상 동작을 확인했습니다. 실제 펌웨어의 초기화 순서까지 전부 재현하지는 못했어요.

여기서 기존 코드를 고치는 선택을 접었습니다. BIOS 계열과 빌더도 폐기했습니다.

CCX를 다시 뜯어보니 0xFF만 써서는 부족했습니다

새 설계의 출발점은 AmdCcxVhAriPei를 다시 역어셈블하는 일이었습니다.

처음에는 SMU Queue 3 메시지 0x98로 presence를 0x77에서 0xFF로 바꾸면 뒤의 CCX 초기화가 8코어를 그대로 받아들일 것으로 예상했습니다.

실제 CCX 코드는 다르게 움직였습니다. 코어 수를 결정할 때 presence 레지스터를 직접 읽지 않고, OPN 토큰과 팩토리 퓨즈를 기준으로 downcore 마스크를 만들었습니다. 출고 OPN이 6코어를 가리키면 CCX가 다시 0x88 마스크를 적용합니다.

0xFF 기록에 성공해도 CCX가 뒤에서 6코어 제한을 다시 걸었습니다.

CCX TE에서는 OPN 6코어를 downcore 토큰 07로 바꿉니다. 이 한 바이트를 Auto를 뜻하는 00으로 바꾸면 CCX가 별도의 6코어 downcore를 적용하지 않습니다.

AmdCcxVhAriPei
OPN downcore token: 07 → 00

새 함수나 초기화 순서를 추가하지 않고 기존 분기값 한 바이트만 바꿨습니다. 이전 실패의 원인이었던 조기 PCD 접근도 없습니다.

PEIM은 언락보다 실패 처리를 더 많이 맡습니다

롬에 삽입한 Bc250CoreUnlockPei는 AMD NBIO SMU 서비스 PPI가 준비되는 시점을 기다립니다. 서비스가 준비되면 아래 조건부터 확인합니다.

BC250 호스트브릿지인가
presence가 정확히 0x77인가
팩토리 core-disable 퓨즈가 0인가
SMU Queue 3가 응답하는가
메시지 0x98로 0xFF 기록
실제 값이 0xFF인지 재확인

SMU 큐의 ready와 completion은 최대 2,500회까지만 읽습니다. 그 안에 응답이 없으면 작업을 중단합니다.

중간 조건이나 하드웨어 접근이 하나라도 실패하면 추가 쓰기를 멈추고 순정 부팅 흐름으로 돌아갑니다. CCX 부팅이 PEIM에 의존하지 않아서, PEIM이 동작하지 않아도 순정 6코어로 부팅됩니다.

첫 새 후보도 콜드 부팅에서는 6코어였습니다

CCX 한 바이트 패치와 notify 방식 PEIM을 넣은 첫 후보는 실보드에서 정상 부팅했습니다. presence는 0xFF, downcore는 0x00으로 확인됐습니다.

그런데 CPU는 여전히 6코어 12스레드였습니다.

SMU가 PEIM보다 먼저 현재 부팅의 코어 구성을 확정했기 때문입니다. PEIM이 값을 제대로 바꿔도 이미 시작된 부팅에는 새 코어 구성이 반영되지 않았어요. 웜 리부트를 한 번 하자 8코어 16스레드가 나타났습니다.

그래서 flip과 리드백 검증까지 성공한 경우에만 PeiServicesResetSystem()을 호출하도록 바꿨습니다.

  • 0x77에서 0xFF 변경 성공: 자동 리셋 1회
  • 이미 0xFF: 리셋 없이 계속 부팅
  • 마스크 불일치, 퓨즈 표시, 큐 오류: 리셋 없이 6코어 부팅

이 조건 덕분에 실패 경로에서는 재부팅 루프가 생기지 않습니다.

최종 롬을 콜드 부팅했을 때 PEIM이 코어 마스크를 바꾸고 자동 리셋한 뒤 nproc = 16으로 올라오는 것을 확인했습니다. 부팅 뒤 측정값은 presence 0xFF, downcore 0x00, fuse-disable 0x00이었습니다.

기존 자동 언락과 무엇이 다른가요?

이번 롬도 내부적으로 자동 리셋을 거쳐 두 번 부팅합니다. 자동 리셋은 기존 방식에도 있습니다.

이번에는 실패 조건을 더 좁게 잡았습니다.

구분이번 롬의 구현
적용 단계PEI의 SMU 서비스 준비 시점
CCX 처리OPN downcore immediate 1바이트를 Auto로 변경
대상 마스크0x77 정확 일치
불량 표시 확인0x5D25C 팩토리 퓨즈 검사
큐 대기2,500회 상한
쓰기 후 처리0xFF 리드백 성공 때만 자동 리셋
실패 경로추가 쓰기와 리셋 없이 6코어 부팅

기존 공개 구현에서 확인한 위험과 제 보드의 실패를 바탕으로, 중단 조건과 6코어 복귀 경로를 펌웨어 안에 넣었습니다.

공개 롬에는 무엇이 들어 있나요?

배포 이미지는 세 부분으로 구성됩니다.

  1. 벤더 순정 P3.00 BIOS와 AMD AGESA
  2. TuxThePenguin0/bc250-bios의 칩셋 메뉴 노출 변경
  3. 이 프로젝트의 CCX 1바이트 패치와 Bc250CoreUnlockPei

언락 변경 외에도 칩셋 메뉴가 노출된 P3.00 베이스를 사용합니다. 이미지에는 제 보드에서 가져온 NVRAM 값도 포함돼 있습니다. 첫 부팅 뒤 설정 화면이나 부팅 항목이 이상하면 CMOS와 NVRAM 초기화가 필요할 수 있습니다.

원래 상태로 돌아갈 때는 공개된 공용 롬보다 플래싱 전에 직접 저장한 보드별 백업을 우선합니다.

sudo flashrom -p internal -w my-stock-backup.rom

운영체제까지 부팅되지 않으면 외부 SPI 프로그래머로 백업 롬을 기록해야 합니다. 이번 칩 교체로 이 복구 경로까지 직접 확인했습니다.

정리하면

공개한 BC250-P3.00-8Core.rom은 콜드 부팅에서 보드 ID, presence 0x77, 팩토리 퓨즈, SMU 큐 응답을 검사합니다. 0xFF 리드백까지 성공하면 자동 리셋하고, 두 번째 부팅에서 8코어 16스레드로 올라옵니다.

펌웨어 내부에서는 두 번 부팅합니다. 사용자가 스크립트를 실행하거나 직접 재부팅할 일은 없습니다.

이 롬은 첫 시도에서 나온 결과물이 아닙니다. BIOS 칩 사망, 새 칩 복구, 시뮬레이션 통과 후보의 실보드 실패를 거친 뒤 기존 구현을 폐기했습니다. CCX 초기화와 PEI 실행 순서를 다시 분석해 남긴 변경은 CCX 한 바이트와 새 PEIM입니다.

PEIM에는 성공 코드보다 중단 조건이 더 많습니다. 8코어를 켜는 것만큼, 조건이 맞지 않을 때 6코어로 부팅하는 과정도 중요했기 때문입니다.

참고 자료

댓글