Содержание:
1. Общие сведения. Legacy-таймеры PIT и RTC.
2. Шина PCI – таймер менеджера питания ACPI.
3. Усовершенствованный таймер HPET.
4. Счётчики процессора LAPIC и TSC (time-stamp-counter).
5. Win - профилирование кода.
---------------------------------------
В первой части рассматривались общие сведения и унаследованные девайсы..
В этой части познакомимся с шиной PCI и более совершенными таймерами наших дней..
ACPI – Advanced Configuration and Power Interface
частота: 3.579545 MHz | счётчик: 24-бит
ACPI пришёл на смену APM (Advanced Power Managament) и представляет собой расширенный интерфейс для настройки и управления питанием аппаратных средств компьютера (актуальна версия 6.3
Контролёр ACPI вобрал в себя три таймера – собственно PM для управления питанием, таймер GPIO (General Purpose IO) и сторожевой watchdog-таймер TCO (прослушивает систему на зависание). Последние два генерируют прерывания SMI (System Managament Interrupt), которые считаются аварийными. Получив SMI процессор немедленно переходит в самый приоритетный свой режим работы SMM, так-что от этих таймеров лучше держаться подальше – мы остановимся лишь на безобидном РМ. Он управляет схемами питания, которые можно просмотреть по powercfg /? в командной строке.
ACPI зарыт глубоко ..и сверху ещё присыпан добрым слоем щебёнки. Нужно приложить немало усилий, чтобы среди паутины шин и устройств раскопать его регистры в системном пространстве. В частности без базовых знаний архитектуры тут не обойтись, поэтому вскроем чипсет как консервную банку и заглянем к нему в душу.
-------------------
Конфигурационное пространство PCI
До недавнего времени, связь буквально всех устройств поддерживала параллельная шина PCI. 32-битной своей артерией она пересекала всю мат.плату сверху-донизу. Более того, со-временем эта шина сама превратилась в устройство, со-своим адресным пространством в ОЗУ. Этот регион памяти назвали
На плате имеются десятки контролёров, поэтому их сортируют по классу. Например все 32-битные девайсы вешают на одну PCI-шину, далее вставляют разделительный мост PCI-to-PCI Bridge и получают вторую шину, которую можно отдать в распоряжении менее скоростных устройств с иным протоколом обмена. Потом добавить ещё мост и открыть доступ абонентам с горячим подключением и т.д. Такое разделение одной шины превращает её в универсальную, где конкретное железо адресуется в формате: шина, устройство на шине, и функция этого устройства – в графическом представлении это выглядит примерно так:
В терминологии PCI, "функция" определяет реальный девайс типа жёсткий диск, а "устройство" – это его контролёр (может быть многофункциональным). Спецификация ограничивает общее число: шин на мат.плате
Но прогресс не стоит на месте и довольно скоро быстродействия пар-шины PCI стало не хватать. Так в архитектуре наших дней её заменили на последовательную PCI-Express с полной переработкой чипсета – на место двойки GMCH и ICH, пришёл один PCH. Теперь имеется центральный Root-Complex, посредством которого девайсы могут общаться между-собой напрямую, ..то-есть получили соединение "Peer-to-Peer" (точка-точка), где каждое устройство считается конечным "Endpoint". Программирование таких чипсетов сводится к поиску базового адреса центрального рута, через который сможем подобраться к любому девайсу чипсета. Отметим, что прежняя схема
Поиск ACPI-контролёра
Но вернёмся к конфигурационному пространству PCI, которое осталось прежним..
Чтобы найти ACPI-контролёр среди груды системного металлолома, сначала нужно узнать шину на которой он висит, а это только через мост. В конфигурационном пространстве данного моста будут прописаны базовые адреса всех девайсов, за которых он отвечает.
Такая цепочка создаёт определённую путаницу, поэтому советую скачать утилиту
Чипсет у меня бородатый ICH7, который при опытах не жалко потерять.
Теперь покончим с теорией шин и перейдём к софт-поиску нужного моста.
Для этого BIOS имеет специальный сервис реального режима
Для доступа к шине PCI выделены два системных порта –
Чтобы не привязывать софт к конкретному чипсету, обычно функцией AX=B103h ищут нужное устройство по его классу. У гугла есть дока
Теперь у нас есть класс LPC-моста = 0х060100, и можно получить его координаты
Описание полей 256-байтного блока LPC-моста указывается в даташите на чипсет. Обратите внимание, что во-избежании путаницы с hex-числами
Здесь видно, что по смещению 40h лежит базовый адрес контролёра ACPI, младший бит которого является флагом достоверности и не учитывается. В данном случае – это номер порта I/O, через который инструкциями
В таблице ниже приводятся номера этих регистров относительно его базового порта. Мы можем получить статус контролёра, залезть в его регистр конфигурации PM1-Control, или через регистр 08h получить доступ к ACPI-таймеру. В доке, к каждому из этих регистров следом прилагается своя таблица битов, и нам остаётся только взводить или сбрасывать их, в зависимости от поставленной задачи:
Здесь видно, что счётчик таймера ACPI имеет разрядность 24-бита, при этом делителя у него нет – он всегда работает на одной частоте 3.579545 MHz. Если в регистре "PM1-Enable" взведён бит нуль, то таймер может генерить прерывания системного контроля SCI (System-Control-Interrupt).
Программирование ACPI-таймера
Проделав этот тернистый путь попробуем написать программу, которая подведёт черту под вышесказанным. Это в теории всё мутно, зато на практике реализовать поиск любого контролёра достаточно просто, ..но только опять-же – если знаешь теорию. Вот пример, в котором комментов больше, чем самого кода. Алгоритм такой:
Программу запускал в реальном режиме под чистым досом. Поскольку клавиша "Prn-Screen" в нём не работает, скрины делал внешней утилитой "snarf.exe", которую прикрепил в скрепке. Там-же есть и софтина для создания загрузочных юсби-брелков.
Здесь я специально вывел регистры в бинарном виде, чтобы показать рычаги управления контролёром ACPI на программном уровне. Каждый бит его регистров вкл/выкл какую-то опцию, и среди этих опций есть весьма не безобидные. Например через регистр "CPU-Control" можно вогнать процессор в режим троттлинга, после чего чипсет начнёт посылать ему холостые такты считая, что он загружен работой по самые помидоры – это приведёт к жутким тормозам. Все "прелести" менеджера питания РМ можно найти в даташите на чипсет, и описывать их тут не имеет смысла.
У этого таймера имеются все шансы стать эталоном времени в системе. При частоте
Что касается интерфейса ACPI в целом, так это огромный механизм с кучей настроек, разобраться в которых не каждому по зубам. В хардвейрных его таблицах BIOS можно найти много интересного, в том числе и OEM-ключ активации Win7-10. В общем тема эта не для части одной статьи, а для двупудового тома. Встретимся в следующей части, где ждёт обзор таймера HPET.
1. Общие сведения. Legacy-таймеры PIT и RTC.
2. Шина PCI – таймер менеджера питания ACPI.
3. Усовершенствованный таймер HPET.
4. Счётчики процессора LAPIC и TSC (time-stamp-counter).
5. Win - профилирование кода.
---------------------------------------
В первой части рассматривались общие сведения и унаследованные девайсы..
В этой части познакомимся с шиной PCI и более совершенными таймерами наших дней..
ACPI – Advanced Configuration and Power Interface
частота: 3.579545 MHz | счётчик: 24-бит
ACPI пришёл на смену APM (Advanced Power Managament) и представляет собой расширенный интерфейс для настройки и управления питанием аппаратных средств компьютера (актуальна версия 6.3
Ссылка скрыта от гостей
). Интерфейс имеет встроенный таймер, по старинке называемый РМ-таймером. Частота 3.5795 MHz, что в 4-раза меньше опорной 14,318. Имеет 24-битный счётчик, продолжающий считать даже в некоторых режимах энергосбережения – это выгодно отличает его от всех остальных таймеров в системе.Контролёр ACPI вобрал в себя три таймера – собственно PM для управления питанием, таймер GPIO (General Purpose IO) и сторожевой watchdog-таймер TCO (прослушивает систему на зависание). Последние два генерируют прерывания SMI (System Managament Interrupt), которые считаются аварийными. Получив SMI процессор немедленно переходит в самый приоритетный свой режим работы SMM, так-что от этих таймеров лучше держаться подальше – мы остановимся лишь на безобидном РМ. Он управляет схемами питания, которые можно просмотреть по powercfg /? в командной строке.
ACPI зарыт глубоко ..и сверху ещё присыпан добрым слоем щебёнки. Нужно приложить немало усилий, чтобы среди паутины шин и устройств раскопать его регистры в системном пространстве. В частности без базовых знаний архитектуры тут не обойтись, поэтому вскроем чипсет как консервную банку и заглянем к нему в душу.
-------------------
Конфигурационное пространство PCI
До недавнего времени, связь буквально всех устройств поддерживала параллельная шина PCI. 32-битной своей артерией она пересекала всю мат.плату сверху-донизу. Более того, со-временем эта шина сама превратилась в устройство, со-своим адресным пространством в ОЗУ. Этот регион памяти назвали
Ссылка скрыта от гостей
, где собраны паспорта всех девайсов, включая выделенные им ресурсы, порты и прерывания. Из общего пула данной памяти, под характеристики каждого из устройств выделяется ровно 256 байт – сколько устройств, столько и 256-байтных блоков.На плате имеются десятки контролёров, поэтому их сортируют по классу. Например все 32-битные девайсы вешают на одну PCI-шину, далее вставляют разделительный мост PCI-to-PCI Bridge и получают вторую шину, которую можно отдать в распоряжении менее скоростных устройств с иным протоколом обмена. Потом добавить ещё мост и открыть доступ абонентам с горячим подключением и т.д. Такое разделение одной шины превращает её в универсальную, где конкретное железо адресуется в формате: шина, устройство на шине, и функция этого устройства – в графическом представлении это выглядит примерно так:
В терминологии PCI, "функция" определяет реальный девайс типа жёсткий диск, а "устройство" – это его контролёр (может быть многофункциональным). Спецификация ограничивает общее число: шин на мат.плате
=256
(0xFF), устройств на одной шине =32
(0x1F), функций у одного девайса =8
.Но прогресс не стоит на месте и довольно скоро быстродействия пар-шины PCI стало не хватать. Так в архитектуре наших дней её заменили на последовательную PCI-Express с полной переработкой чипсета – на место двойки GMCH и ICH, пришёл один PCH. Теперь имеется центральный Root-Complex, посредством которого девайсы могут общаться между-собой напрямую, ..то-есть получили соединение "Peer-to-Peer" (точка-точка), где каждое устройство считается конечным "Endpoint". Программирование таких чипсетов сводится к поиску базового адреса центрального рута, через который сможем подобраться к любому девайсу чипсета. Отметим, что прежняя схема
Bus:Dev:Func
тоже жива, только сброшена в подвал на растерзание Legacy-устройствам:Поиск ACPI-контролёра
Но вернёмся к конфигурационному пространству PCI, которое осталось прежним..
Чтобы найти ACPI-контролёр среди груды системного металлолома, сначала нужно узнать шину на которой он висит, а это только через мост. В конфигурационном пространстве данного моста будут прописаны базовые адреса всех девайсов, за которых он отвечает.
Такая цепочка создаёт определённую путаницу, поэтому советую скачать утилиту
Ссылка скрыта от гостей
. Этот зверь достанет инфу о любом корневом устройстве на шине PCI, причём в очень наглядном виде со-значениями всех полей выделенного ему 256-байтного блока. Вот как выглядит топология на моей экспериментальной машине:Чипсет у меня бородатый ICH7, который при опытах не жалко потерять.
Ссылка скрыта от гостей
на него даташит и маской поиска "ACPI Base" обнаруживаю, что ACPI-контролёр висит на шине LPC (Low-Pin-Count). Значит в общем кфг-пространстве нужно будет найти мост PCI-to-LPC и прочитать его 256-байтный блок регистров. На рис.выше тулза дала уже мне наводку на него в виде Bus[00]:Dev[1F]:Func[00]
, и остаётся только жмякнуть по ней мышью:Теперь покончим с теорией шин и перейдём к софт-поиску нужного моста.
Для этого BIOS имеет специальный сервис реального режима
INT-1Ah
, а халёный EFI его эмулирует:Для доступа к шине PCI выделены два системных порта –
0CF8h
(конфигурация) и 0CFCh
(данные), так-что можно работать с шиной и через эти порты. Однако готовый сервис PCI-BIOS избавляет нас от кропотливой возни с битами, хотя и решает не все задачи. Но в большинстве случаях указанных функций бывает достаточно, чтобы (без шума и пыли) найти и прочитать данные из конфигурационного пространства устройств.Чтобы не привязывать софт к конкретному чипсету, обычно функцией AX=B103h ищут нужное устройство по его классу. У гугла есть дока
Ссылка скрыта от гостей
, где перечислены классы всех системных девайсов. Фрагмент из этой доки для мостов Bridge представлен ниже, а базу вендоров VEN-DEV можно стянуть от сюда:Теперь у нас есть класс LPC-моста = 0х060100, и можно получить его координаты
Bus:Dev:Func
примерно так..
C-подобный:
mov eax,0xB103 ;// поиск устройства по классу
mov ecx,0x060100 ;// класс\подкласс\интерфейс
xor esi,esi ;// искать без цикла один девайс
int 1Ah ;// зовём сервис PCI-BIOS !!!
jc @error ;// ошибка, если флаг CF=1.
;// ---------------
;// иначе: в регистре ВХ лежат B:D:F Lpc-моста,
;// что позволит читать данные из его cfg-пространства.
Описание полей 256-байтного блока LPC-моста указывается в даташите на чипсет. Обратите внимание, что во-избежании путаницы с hex-числами
A-F
, Intel представляет номер шины, устройства и функции в 10-тичном, т.е. под D31:F0
нужно понимать Dev[1F]:Func[00]
Здесь видно, что по смещению 40h лежит базовый адрес контролёра ACPI, младший бит которого является флагом достоверности и не учитывается. В данном случае – это номер порта I/O, через который инструкциями
IN/OUT
мы и будем вести диалог с контролёром. Таким образом, теперь у нас есть PMBASE и можно приступать к чтению/записи непосредственно регистров ACPI.В таблице ниже приводятся номера этих регистров относительно его базового порта. Мы можем получить статус контролёра, залезть в его регистр конфигурации PM1-Control, или через регистр 08h получить доступ к ACPI-таймеру. В доке, к каждому из этих регистров следом прилагается своя таблица битов, и нам остаётся только взводить или сбрасывать их, в зависимости от поставленной задачи:
Здесь видно, что счётчик таймера ACPI имеет разрядность 24-бита, при этом делителя у него нет – он всегда работает на одной частоте 3.579545 MHz. Если в регистре "PM1-Enable" взведён бит нуль, то таймер может генерить прерывания системного контроля SCI (System-Control-Interrupt).
Программирование ACPI-таймера
Проделав этот тернистый путь попробуем написать программу, которая подведёт черту под вышесказанным. Это в теории всё мутно, зато на практике реализовать поиск любого контролёра достаточно просто, ..но только опять-же – если знаешь теорию. Вот пример, в котором комментов больше, чем самого кода. Алгоритм такой:
1. Проверяем поддержку сервиса PCI-BIOS – выходим, если нет.
2. Организуем поиск моста PCI-to-LPC по его классу 0х060100.
3. Получив
Bus:Dev:Func
моста, читаем из его кфг-пространства регистр 40h – PMBASE.4. Теперь у нас есть базовый порт ACPI-контролёра, и можно читать с него любые регистры.
5. Выводим всю инфу на консоль.
C-подобный:
;// fasm (Real-Mode)
;// Читает регистры ACPI-контролёра
;// тестировалось на чипсете "Intel ICH7"
;// -------------
org 100h
jmp start
caption db 13,10,' ACPI info v.01 '
db 13,10,' ======================'
db 13,10,' Support PCI-BIOS.: $'
totalBus db 13,10,' Total PCI-bus....: $'
find db 13,10
db 13,10,' Find LPC bridge... $'
lpcInfo db 13,10,' PCI-Bus.......: $'
device db 13,10,' PCI-Device....: $'
func db 13,10,' PCI-Function..: $'
vid db 13,10,' VendorID......: $'
did db 13,10,' DeviceID......: $'
acpiInfo db 13,10
db 13,10,' ACPI controller'
db 13,10,' I/O port......: 0x$'
rcBar db 13,10,' Root-Complex..: 0x$'
acpiReg db 13,10
db 13,10,' ACPI registers'
db 13,10,' PM1 status....: $' ;//регистр(00h)
pmEn db 13,10,' PM1 enable....: $' ;//регистр(02h)
pmCtl db 13,10,' PM1 control...: $' ;//регистр(04h)
pmTmr db 13,10,' Timer value...: $' ;//регистр(08h)
cpuCtl db 13,10,' CPU control...: $' ;//регистр(10h)
smiCtl db 13,10,' SMI ctl_enable: $' ;//регистр(30h)
smiStat db 13,10,' SMI status....: $' ;//регистр(34h)
;// Таблица для расшифровки Device-ID.
;// старший байт DevID совпадает с типом чипсетов ICH6-9.
devTable dw 0x2600,i6,0x2700,i7,0x2800,i8
dw 0x2900,i9,0x3A00,i10,0x3B00,pch
dtLen = ($ - devTable)/4
i6 db ' = ICH6 $'
i7 db ' = ICH7 $'
i8 db ' = ICH8 $'
i9 db ' = ICH9 $'
i10 db ' = ICH10. Chipset not support $'
pch db ' = PCH. Chipset not support $'
unkNown db ' = Unknown bridge $'
;//=====================================================
mError db 'ERROR!$'
ok db 'OK! $'
bdf dw 0
pmBase dd 0
rcba dd 0
;//--------
start:
mov dx,caption ;// шапка
call Message ;//
;//--- Проверяем поддержку fn.PCI-BIOS
mov ax,0xB101 ;// fn.0xB101
xor edi,edi ;//
int 1Ah ;// зовём сервис!
or ah,ah ;//
jz @f ;// ОК, если AH=0
call ERROR ;// иначе: ошибка.
@@: push cx ;// запомнить кол-во шин
mov dx,ok ;// есть PCI-BIOS!
call Message ;//
mov dx,totalBus ;// всего шин.
call Message ;//
pop ax ;// снять их со-стека
and ax,0xff ;// оставить только мл.байт
inc al ;// +1, т.к.отсчёт с нуля
mov bx,10 ;// система счисления
call Hex2Asc ;// Print-AX
;//-----------------------------------------------
;//--- Поиск моста "PCI-to-LPC" по его классу ----
;// Возвращает в регистр ВХ [bus:dev:func]
;// BH=Bus, BL[7:3]=Device, BL[2:0]=Function.
;//-----------------------------------------------
mov dx,find ;//
call Message ;//
mov ax,0xB103 ;// fn.0xB103
mov ecx,0x060100 ;// класс\подкласс\интерфейс
xor si,si ;// искать без цикла 1 устройство
int 1Ah ;// Найти!
jnc @f ;// если флаг CF=0, то Forward (вперёд)
call ERROR ;// иначе: ошибка
@@: mov [bdf],bx ;// запомнить выхлоп "Bus:Dev:Func"
push bx bx bx ;// в стек их, для вывода на консоль.
mov dx,ok ;// мессага "Найдено"!
call Message ;//
;// Выводим эти данные на консоль
;// == Bus ==
mov dx,lpcInfo ;//
call Message ;//
pop ax ;//
shr ax,8 ;// оставляем только ст.часть[15:8]
mov bx,16 ;// система счисления
call Hex2Asc ;//
;// == Device ==
mov dx,device ;//
call Message ;//
pop ax ;//
xor ah,ah ;//
shr ax,3 ;// оставляем биты[7:3]
mov bx,16 ;//
call Hex2Asc ;//
;// == Function ==
mov dx,func ;//
call Message ;//
pop ax ;//
and ax,111b ;// оставляем биты[2:0]
mov bx,16 ;//
call Hex2Asc ;//
;//-----------------------------------------
;//--- Читаем из кфг.пространства LPC-моста
;//--- его идентификаторы VEN\DEV
;//-----------------------------------------
mov ax,0xB10A ;// fn= читать двордами (по 4-байт)
mov bx,[bdf] ;// от куда "Bus:Dev:Func"
xor di,di ;// адрес = 0 (offs.от начала)
int 1Ah ;//
push ecx ecx ;// запомнить VEN\DEV для вывода
;//--- Читаем поле "APCI-base" (порт контролёра)
mov ax,0xB10A ;// размер = 4-байта
mov bx,[bdf] ;// координаты
mov di,0x40 ;// смещение 40h от начала LPC-cfg
int 1Ah ;//
dec ecx ;// сбросить бит валидности адреса.
mov [pmBase],ecx ;// запомнить в переменной.
;//--- Читаем поле "Root-Complex BA"
mov ax,0xB10A ;//
mov bx,[bdf] ;//
mov di,0xf0 ;// смещение F0h
int 1Ah ;//
mov [rcba],ecx ;// запомнить RCBA.
;//----------------------------------------
;//--- Выводим нарытую инфу на консоль ----
;//----------------------------------------
;// *** Vendor-ID ***
mov dx,vid ;//
call Message ;//
pop eax ;// снимаем со-стека считанное
movzx eax,ax ;// обнулить старшую часть
mov ebx,16 ;// система-счисления
call Hex2Asc ;// Print-AX
;// *** Device-ID ***
mov dx,did ;//
call Message ;//
pop eax ;//
shr eax,16 ;// обнулить младшую часть
push ax ;// запомнить DevID
mov ebx,16 ;//
call Hex2Asc ;// Print его на консоль.
;// Определяем тип моста по его DevID
pop bx ;//
and bx,0xFF00 ;// очистить мл.байт
mov esi,devTable ;// указатель на таблицу
mov ecx,dtLen ;// ..её длина
@@: lodsd ;// берём в EAX сразу 4-байта из SI
cmp ax,bx ;// ищем совпадения младшего слова
je @f ;// ..(в старшем лежит адр.мессаги)
loop @b ;// повторить, если не равно
mov dx,unkNown ;// нет совпадений.
call Message ;//
jmp @acpi ;//
;// Нашли DevID в своей базе!
@@: shr eax,16 ;// сместить адрес текста в АХ
mov dx,ax ;// вывести его на консоль.
call Message ;//
;// *** ACPI Base Address ***
@acpi: mov dx,acpiInfo ;//
call Message ;//
mov eax,[pmBase] ;//
mov ebx,16 ;//
call Hex2Asc ;// Print-ЕAX
;// *** Root Complex Base Addr ***
mov dx,rcBar ;//
call Message ;//
mov eax,[rcba] ;//
mov ebx,16 ;//
call Hex2Asc ;// Print-ЕAX
;//-----------------------------------------------------------
;//--- В переменной "PMBASE" лежит номер порта ACPI-контролёра
;//--- читаем его регистры на консоль ------------------------
;//-----------------------------------------------------------
mov dx,acpiReg ;//
call Message ;//
mov edx,00h ;// ..регистр в нём "PM1_Status"
call ReadAcpiPort ;//
mov ecx,16 ;// кол-во бит для вывода
call Bin2Asc ;// Print-AX в бинарном виде!
mov dx,pmEn ;//
call Message ;//
mov edx,02h ;// ..регистр в нём "PM1_Status"
call ReadAcpiPort ;//
mov ecx,16 ;//
call Bin2Asc ;//
mov dx,pmCtl ;//
call Message ;//
mov edx,04h ;// ..регистр в нём "PM1_Status"
call ReadAcpiPort ;//
mov ecx,32 ;// кол-во бит для вывода
call Bin2Asc ;// Print-EAX в бинарном!
mov dx,pmTmr ;//
call Message ;//
mov edx,08h ;// ..регистр в нём "PM1_Status"
call ReadAcpiPort ;//
mov ebx,10 ;// система-счисления для вывода
call Hex2Asc ;// Print-EAX в 10-тичном!
mov dx,cpuCtl ;//
call Message ;//
mov edx,10h ;// ..регистр в нём "PM1_Status"
call ReadAcpiPort ;//
mov ecx,32 ;//
call Bin2Asc ;//
mov dx,smiCtl ;//
call Message ;//
mov edx,30h ;// ..регистр в нём "PM1_Status"
call ReadAcpiPort ;//
mov ecx,32 ;//
call Bin2Asc ;//
mov dx,smiStat ;//
call Message ;//
mov edx,34h ;// ..регистр в нём "PM1_Status"
call ReadAcpiPort ;//
mov ecx,32 ;//
call Bin2Asc ;//
@exit: ;//
xor ax,ax ;//
int 16h ;//
int 20h ;//
;//===============================
;// === ДОП.ФУНКЦИИ ==============
ReadAcpiPort: ;//<------ на входе: EDX = регистр.
add edx,[pmBase] ;// добавить базовый порт.
in eax,dx ;// считать данные в ЕАХ
retn
Hex2Asc: ;//<------ Перевод чисел в символы
xor ecx,ecx ;// описание смотри,
isDiv: xor edx,edx ;// ... в первой программе.
div ebx ;//
push edx ;//
inc ecx ;//
or eax,eax ;//
jnz isDiv ;//
isOut: pop eax ;//
cmp al,9 ;//
jle noHex ;//
add al,7 ;//
noHex: add al,30h ;//
int 29h ;//
loop isOut ;//
retn
Bin2Asc: ;//<------ Вывод в BIN
mov ebx,eax ;// взять число в EBX
or ebx,ebx ;// проверить его на нуль
jne @f ;// продолжить, если больше -----+
mov al,'0' ;// иначе: вывести 0 |
int 29h ;// ..и возвратить управление. |
retn ;// |
@@: cmp cx,32 ;// проверить аргумент на 32 <---+
je @f ;// если равно..
shl ebx,16 ;// иначе: число влево на 16-бит
@@: mov al,'0' ;// в дефолте выводить нуль
shl ebx,1 ;// выталкиваем по 1-биту влево..
jnc okey ;// если CF=0
inc al ;// иначе: +1
okey: int 29h ;// вывести бит на консоль
loop @b ;// промотать цикл СХ-раз
retn
Message: ;//<------ Вывод строк
mov ah,9 ;//
int 21h ;//
retn
ERROR: pop ax ;//<------ снять адрес возврата
mov dx,mError ;// мессага
call Message ;//
jmp @exit ;// на выход!
Программу запускал в реальном режиме под чистым досом. Поскольку клавиша "Prn-Screen" в нём не работает, скрины делал внешней утилитой "snarf.exe", которую прикрепил в скрепке. Там-же есть и софтина для создания загрузочных юсби-брелков.
Здесь я специально вывел регистры в бинарном виде, чтобы показать рычаги управления контролёром ACPI на программном уровне. Каждый бит его регистров вкл/выкл какую-то опцию, и среди этих опций есть весьма не безобидные. Например через регистр "CPU-Control" можно вогнать процессор в режим троттлинга, после чего чипсет начнёт посылать ему холостые такты считая, что он загружен работой по самые помидоры – это приведёт к жутким тормозам. Все "прелести" менеджера питания РМ можно найти в даташите на чипсет, и описывать их тут не имеет смысла.
У этого таймера имеются все шансы стать эталоном времени в системе. При частоте
3.579545
MHz его разрешение: 1/3579545 =279
ns, а это вполне приличная единица. Однако имеется одна проблема, из-за которой система относится к нему насторожено – это обвальное падение производительности при высокой загруженности шины PCI. В этом случае РМ-таймер не успевает во-время отправлять свои тики по шине, и хотя они при этом не пропадают, счётчик на приёмной стороне обновляется рывками, в промежутке которых может произойти что-то важное. По этой причине самым надёжным таймером считается тот, который физически расположен ближе к процессору, например LAPIC или TSC.Что касается интерфейса ACPI в целом, так это огромный механизм с кучей настроек, разобраться в которых не каждому по зубам. В хардвейрных его таблицах BIOS можно найти много интересного, в том числе и OEM-ключ активации Win7-10. В общем тема эта не для части одной статьи, а для двупудового тома. Встретимся в следующей части, где ждёт обзор таймера HPET.
Вложения
Последнее редактирование: