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 :