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
<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"