[Измерение температуры процессора AMD64]
[Преамбула]
Неожиданно при измерении температуры процессора CoreTemp - ом захотелось научиться это делать самостоятельно. Как видно из заголовка я обладатель процессора AMD.
Почему я это решила запостить? Да как-то пока материал искала, наткнулась на несколько тем на форумах, но примера нормального так и не нашла (а вопросы такие периодически возникают). Материал практический, по теории достаточно в манах AMD. Я только кратко обрисую основные теоретически моменты.
[Coding]
Чтобы узнать текущую температуру нам потребуется доступ к так называемому Thermtrip Status Register. Его формат
Чтобы прочитать значение Thermtrip Status Register для каждого ядра, нам потребуется доступ к конфигурационному пространству PCI.
Для доступа к устройствам на шине PCI существует 2 порта - 0xCF8 и 0xCFC. Порт 0xCF8 именуется CONFIG_ADDRESS (0xCF8) и в него заносится значение в формате
Порт 0xCFC или CONFIG_DATA предназначен для чтения/записи данных в конфигурационное пространство. Сначала мы должны выбрать нужное устройство посредством регистра CONFIG_ADDRESS, а потом прочитать данные из CONFIG_DATA (чуть забегая вперед записывать в CONFIG_DATA тоже придется при выборе ядра).
Теперь перейдем непосредственно к кодингу. Для удобства формирования CONFIG_ADDRESS приведу 2 функции (взято из книженции "Программирование Аппаратных средств в Windows", глава 12 "Пространство шины PCI"):
Код:
int GetDeviceSlot(int iDevice,int iFunction){
return ((((iDevice)&0x1f)<<3)|((iFunction)&0x07));
}
ULONG GetDevice(int iBus,int iSlot,int iAddress){
return (0x80000000L |((iBus&0xff)<<16)|(iSlot<<8)|(iAddress&~3));
}
Таким образом, мы вызываем так
Код:
GetDevice(0,GetDeviceSlot(24,3),0xE4);
То есть:
Bus:0
Device:24
Function:3
Offset:0xE4
Почему такие значения? Все это из документации (ссылки на нее в конце).
Ясное дело, что ядра у нас может быть 2. Тогда смотрим еще раз внимательно на формат Thermtrip Status Register и видим бит ThermSenseCoreSel, отвечающий как раз за выбор ядра. Если второй бит от нуля (ThermSenseCoreSel) будет равен 0, то мы проверяем температуру первого ядра, если 1- второго. Итак, полный код функции, которую следует поместить в драйвер
Код:
VOID GetTemperature(VOID){
ULONG therm_=0,core=0,conf_data;
ULONG cdata = GetDevice(0,GetDeviceSlot(24,3),0xE4);
//пишем в Configuration Address Register
_outpd(0xCF8,cdata);
// читаем Configuration Data Register
therm_ = _inpd(0xCFC);
conf_data = therm_;
//с каким ядром имеем дело
core=therm_;
core=(core>>2)&1;
//нам нужны биты 23:14
therm_=(therm_>>14)&(0x3FF);
//вычисляем реальную температуру ядра по формуле
therm_=(therm_/4)-49;
KdPrint(("Temperature Core%d: %d C",core,therm_));
//проверяем другое ядро
conf_data = conf_data^4;
//пишем в Configuration Address Register
_outpd(0xCF8,cdata);
//выбираем другое ядро
_outpd(0xCFC,conf_data);
//пишем в Configuration Address Register
_outpd(0xCF8,cdata);
// читаем Configuration Data Register
therm_ = _inpd(0xCFC);
conf_data = therm_;
//с каким ядром имеем дело
core=therm_;
core=(core>>2)&1;
//нам нужны биты 23:14
therm_=(therm_>>14)&(0x3FF);
//вычисляем реальную температуру ядра по формуле
therm_=(therm_/4)-49;
KdPrint(("Temperature Core%d: %d C",core,therm_));
}
Получилось что-то вроде...
*Тестировалось на Amd Athlon 64 x2 Dual Core, ОС WinXPSP3
[Что читать?]
Ну если тема интересна, то могу порекомендовать по AMD
[1] Мануалы от производителя.
http://developer.amd.com/documentation/guides/Pages/default.aspx#developer_guides
[2].Хорошая статья, которая помогла мне связать все воедино
Реализация низкоуровневой поддержки шины PCI в ядре Linux
http://www.opennet.ru/base/dev/pci_linux_kernel.txt.html
конкретно по сабжу будет полезен раздел "Конфигурационное пространство устройства PCI", там как раз про Configuration Mechanism, CONFIG_ADDRESS, CONFIG_DATA. Как прочтете это - сразу все в голове уложится.
PS В общем-то посредством пм со мной можно связаться и какой-то момент уточнить.
PSS Сессия, мать ее, моя первая сессия. Чувствую себя ботом, сконфигурированным на заучивание конспектов.... (