RX480 써멀 재도포 이후 팬을 컨트롤하는 놈이 궁금해졌다. 


어떠한 원리로 컨트롤 하는지 알고 싶기 떄문에 RX480을 분석하기로 한다.




<Fig1. Fan Pinout>


RX480의 쿨러는 4PIN을 사용하고 있다. 그림 1과 같이


검은색 = GND

노란색 = +12V

녹색 = Senser

파란색 = Control


으로 구성되어 있다.



<Fig2. signal>


로직 애널라이저로 Sensor pin을 확인하면 Pulse-width modulation (PWM)로 구성되어 있는 것을 확인할 수 있다.


참고 자료 : https://en.wikipedia.org/wiki/Pulse-width_modulation


보드에서 FAN의 속도를 조절하기위해 FAN 전압을 GPU에 sending 한뒤 GPU쿨러의 센서가 현재의 RPM을 response하여 온도관리 한다.

따라서 쿨러의 현재 RPM을 전송하지 못하여도 메인보드에선 전압을 통해 FAN을 제어 하여 지속적으로 전압을 전송하기 때문에 온도 조절이 되지 않아 GPU 가 타는 불상사가 일어날 수 있다.

그렇기 때문에, GPU가 특정 온도 이상 올라가면 자동으로 GPU의 전원을 차단하는데 이는 하드웨어적으로 구현하기에는 상당히 무리가 있어 분명 어딘가에 저장할 것이라고 판단하였다 . 제일 의심 가는 부분은 바로 BIOS다.



<Fig3. BIOS Version>



TechPowerUP 도구를 사용하여 RX480의 바이오스를 추출할 수 있다. 물론 플래싱 까지 가능하다.



<Fig4. BIOS Extract>


해당 바이오스 펌웨어는 당연히 Binwalk에서도 아무것도 할 수 없다.


삽질을 통해 분석한 결과...



<Fig5. BIOS Analysis>


해당 구조로 구성되어 있는 것을 확인할 수 있다.

조금 설명하자면 Little Endian으로 기록되어 있으며, 처음에는 AMD Magic signature로 추정되는 0x55AA가 기록되어 있으며 (linux kernel AMD gpu driver 참고함) 현재의 총 블럭 개수가 기록되어 있다. 이후 식별된 데이터는 Block의 크기가 기록되어 있어 해당 영역은 0x73 * 0x200 = 0xE600 만큼 크기인것을 확인할 수 있다. 이후 확인한 CheckSum이였으며,  계산 원리는 간단하다. 0번지 offset부터 사이즈 만큼 모든 byte를 더한 값이 CheckSum 데이터이다.


또한 온도 기록방식도 특이하였다. 최대 온도를 예를 들어 0x2134 이며 계산 식은 0x2134  / 0x64 = 0x55 (85) 인것을 확인할 수 있다.


RX480의 바이오스는 무결성 확인이 없기 때문에 아무나 수정해서 올릴 수 있다. 따라서 최대 온도와 RPM 온도 등의 설정정보를 범위 이상으로 놓으면 (?).....


온도 관련된 정보들은 어느정도 찾았으니 나머지는 여러분이 분석해보길 바란다.




<Fig6. cool!>


바이오스 수정해서 올리지 마세요. 벽돌 될 수 있습니다. 전 못고치며 모든 책임은 당신에게 있습니다.


import struct

rom_checksum = 0x21
venderid = 0x238
subid = 0x23A
deviceid = 0x24A
subvendorid = 0x238
min_temp = 0x9ED8
med_temp = 0x9EDA
high_temp = 0x9EDC
max_temp = 0x9EE4
max_RPM = 0x9EEB 
max_gpufreq = 0x9C59
max_memory_freq = 0x9C5D
power_control_limit = 0x9C61
shutdown_temp = 0x9F1D 
max_temp_power = 0x9F17

print "################################"
print "# RX480 Bios Analysis v0.01    #"
print "#                              #"
print "#             hacked by koha   #" 
print "################################\n"

f=open("bios.rom","rb")
databuffer = f.read()
f.close()

checksum = struct.unpack("B",databuffer[rom_checksum])[0]
size = struct.unpack("B",databuffer[0x02])[0] * 0x200

check=0
for i in range(size):
    check += struct.unpack("B",databuffer[i])[0]
check = checksum - (check % 0x100)
if checksum == check:
    print "Checksum ok\n"

print "vendor ID : " + databuffer[venderid:venderid+2].encode('hex')
print "Sub ID : " + databuffer[subid:subid+2].encode('hex')
print "device ID : " + databuffer[deviceid:deviceid+2].encode('hex')
print "subvendor ID : " + databuffer[subvendorid:subvendorid+2].encode('hex')+"\n"




Posted by kkoha :


14나노 핀펫 공정으로 만든 RX480은 래퍼런스 제품이 30만원 밖에(?) 안하는 가격으로 가성비 괜찮은 제품 중 하나인데.... 발열량이 상당하다. 따라서 14,000원만 투자하여 써멀 구리스 재도포를 통해 온도를 낮춰보려고 한다.



<Fig1. RX480>


그래픽 카드 기준으로 옆면 각각 3개의 나사를 제거하면 블로워팬 뚜껑을 딸 수 있다.


<Fig2. rx480 heat sink>


뚜껑 따면 은색의 싸구려 히트싱크를 볼 수 있다.


히트싱크를 분리하려면 보드 뒤편에 있는 브라켓을 분리해야 하는데 이 브라켓을 고정하는 피스 중 하나에 AMD 워런티 씰이 존재한다. 얘 없어지면 3년 무상 a/s 사라진다...


워런티 씰 우회는 드라이기 신공 등 여러 신공이 있지만


<Fig3. warranty seal stickers>


브라켓에서 4개 중 씰 없는 나사 3개 분리 이후 그림4 와 같이 빙빙 돌리면 워런티 씰 보존 상태에서 브라켓 분리가 가능하다. (취.약.점) 당연히 역순으로 조립할 수 있다.


<Fig4. warranty seal stickers >


히트팬 분리하면 기존에 발라져 있던 써멀의 흔적을 볼 수 있다. 말끔히 제거하자.


<Fig5. rrreeemmooovvee>


ARCTIC MX-4 thermal compond (Thermal Conductivity: 8.5 W/mK) 출동!!


<Fig6. MX-4>


GPU 중간에 1자로 도포 한뒤 역 조립한다.



<Fig7. 111111>


동일 환경에서  3d mark fire strike 2번 테스트 한 결과다. fire strike(이하 파스) 보는거 정말 지겹다.


일반 상태에서 재부팅 이후 파스 테스트 시 최소 44도 ~ 최대 90도


<Fig8. Normal>


서멀 교체 이후 파스 테스트 시 최소 39도 ~ 최대 84도


<Fig9. Replace thermal compound>


온도는 내려갔으나 fan speed가 요동을 친다... 음..??


사실상 DIY 종결판 RX480...;;;

Posted by kkoha :

티몬에서 UHD TV를 싸게 팔고 있어 해피머니 10만원당 93000원에 구매해서 티몬 캐쉬 30만원 충전한뒤 구입하니 더 싸졌다 +_+ 




<Fig1. 득템>



어쨋든 이놈은 태생이 TV인지라 기본으로 Sharp filter가 적용되어 있기 때문에 모니터로 쓰기엔 가독성이 너무 떨어진다. 


구글링을 통해 유출인지 찾은건진 모르겠지만 어떤 능력자가 관리자 모드 (팩토리 모드)를 공개줬다.  


(리모콘에서 메뉴 -> 1147 입력)


<Fig2. 팩토리 모드>




팩토리 모드에서 Sharp filter를 끌 수 있지만 재부팅하면 다시 초기화되는 치명적(?) 약점을 가져 아예 펌웨어 분석한 뒤 디폴트로 Sharp를 없애려고 분석을 시작했다.





<Fig3. 왜 찾질 못하니>



펌웨어 파일은 4메가 정도 되며 펌웨어 구조 분석한 문서가 아무것도 없다. 


또한 binwalk에도 만 가득 출력되서 직접..펌웨어 포맷을 분석하는 방법 밖에 없다....




처음으로 UHD를 샀고.......a/s도 2년 짜리라.........감히 Teardown을 못하겠다......UART를 찾아야 빠른데...... 안돼! a/s받아야돼!!


맨땅에 해딩 ㄱㄱㄱ



<Fig4. UHD로 디아 하면 짱임>



0x22080 부터 file 구조체가 있는 것을 확인할 수 있다. 4byte ADDR, 4byte SIZE, 3byte Type 순으로 기록되어 있는 것을 확인할 수 있다.


<Fig5. Zepa firmware file structure>


구조 파악했으니 얼릉 분리하고 분석 해봐야징 ^^*



<Fig6. Zepa firmware extract>


fig7는 분해된 데이터이며 ZEPA TV 있는 사람이라면 부팅 시 나오는 로고인  DIGITAL LED TV가 00308d10.jpg 파일로 존재하는 것을 확인할 수 있다.


<Fig7. files>



식별 할 수 있는 파일들은 확장자로 구분했다.


해당 TV의 OS는 embedded Linux이며 모든 관리는 커널에서 관리한다.


분석해보니 HDMI 2.0 쓰면 TV에서 알아서 그래픽 모드로 진입해서 SHARP 기능을 끄는 루틴이였다;; 


이후 GTX 970 사서 껴보니 Sharp filter가 자동으로 꺼졌다! ㅎ...........


더 상세한 내용은 저작권(?) 문제가 될 수 있으니, 자세한건 여러분이 분석하세요. 


펌웨어 수정해서 올리지 마세요. 벽돌 될 수 있습니다. 전 못고치며 모든 책임은 당신에게 있습니다.


얘는 크로마 서브샘플링(Chroma subsampling)을 지원하니 출력색은 ycbcr444으로 하세용^^*


import struct

print "##############################################"
print "#           Zepa Firmware Extractor v0.01    #"
print "#                                            #"
print "#             hacked by koha  #"
print "##############################################\n"

f=open("MSD3458_8M.bin","rb")

f.seek(0x22090)
addrl=[]
sizel=[]
for i in range(20):
    addr = f.read(4)
    addrl.append(addr)
    size = f.read(4)
    sizel.append(size)
    unknown = f.read(3)
    print str(i)+" : "+addr.encode('hex') +  " "+size.encode('hex')

for i in range(len(addrl)):
    addr = struct.unpack('>l',addrl[i])[0]
    size = struct.unpack('>l',sizel[i])[0]
    f.seek(addr)
    data = f.read(size)
    fname =  addrl[i].encode('hex')+".bin"
    if data[0] == "\x5D":
        fname =  addrl[i].encode('hex')+".lzma"
    if data[:3] == "\xff\xd8":
        fname =  addrl[i].encode('hex')+".jpg"
    open(fname,"wb").write(data)


Posted by kkoha :