пятница, 18 декабря 2015 г.

Watchdog timer

На одном обслуживаемом объекте промышленный компьютер выполняющий важные круглосуточные задачи по непонятным причинам периодически повисает стабильно раз в неделю. Длительное исследование проблемы результатов не дало, и сложилось стойкое убеждение что причина - дефект одного из компонентов материнской платы, т.е. чисто железная проблема. Было предложено задействовать встроенный в мать watchdog таймер, реализованный на чипе winbond w83627 представляющий Super I/O контроллер. Но одно дело выдвинуть идею, другое - ее воплотить. Этим и займемся...

В описании на чип приводятся инструкции для работы с таймером через ряд регистров центрального процессора. Поэтому первейшей задачей было найти возможность достучаться до kernel регистров с user слоя операционной системы Windows XP/Seven 32bit. Стандартный способ требует наличия функционального или интерфейсного драйвера для доступа к аппаратуре, библиотеки выступающей оберткой над драйвером с набором клиентского API и собственно самого клиента, реализующего алгоритм управления таймером. Главное здесь это код драйвера, который можно написать с нуля, либо использовать готовые шаблоны например GiveIO. Однако проще драйвер вообще не писать, а воспользоваться таким проектом как Inpout32. Данная сборка включает в себя готовый драйвер, его установщик, библиотеку и примеры использования. Проект открытый, поэтому имеются и все исходники, что не может не радовать. Имея все это на руках можно переходить к реализации клиента. Я буду использовать Ultimate++, который подходит идеально для таких задач.

Общая схема работы WDT следующая: (1) активация; (2) установка интервала срабатывания; (3) запуск; (4) периодический сброс; (5) останов; (6) деактивация. Таймер в рабочем режиме выполняет отрицательное приращение счетчика времени от интервала срабатывания и по достижении нуля производит сброс ЦПУ. Если не восстанавливать счетчик таймера, последний будет продолжать сбрасывать ЦПУ, что конечно нежелательно. Клиентская программа должна до наступления порога срабатывания таймера сбрасывать его в начальное состояние , тем самым заставляя таймер начинать работу заново. И только в случае зависания ЦПУ, когда он не может исполнять инструкции, WDT произведет его сброс и произойдет перезапуск системы.

Работа с Super I/O контролером w83627 ведется от имени ЦПУ при помощи двух регистров 2Eh и 2Fh. Первый используется для задания адреса порта ввода/вывода, второй - для записи в порт/чтения из порта данных.

Библиотека Inpout32.dll предлагает две функции Out32(short, short) и Inp32(short). Первая применяется для установки адреса порта ввода/вывода и записи в порт значения. Вторая - для чтения данных из порта ввода/вывода во внешнюю переменную с типом short.

Для примера рассмотрим код клиента на С который пытается задействовать таймер в режиме счета секунд.

// ; unlock chip
//mov dx, 2Eh
//mov al, 87h
//out dx, al
//out dx, al
Out32(0x2E, 0x87);
Out32(0x2E, 0x87);
// ; select registers of WDT
//mov al, 07h
//out dx, al
//inc dx
//mov al, 08h
//out dx, al
Out32(0x2E, 0x07);
Out32(0x2F, 0x08);
// ; enable the function of WDT
//dec dx
//mov al, 30h
//out dx, al
//inc dx
//mov al, 01h
//out dx, al
Out32(0x2E, 0x30);
Out32(0x2F, 0x01);
// ; set second as counting unit
//dec dx
//mov al, f5h
//out dx, al
//inc dx
//in al, dx
//and al, not 08h
//out dx, al
Out32(0x2E, 0xF5)
Out32(0x2F, 0x08 & (Inp32(0x2F) & 0xFF);
// ; set timeout interval ? as unit and start counting
//dec dx
//mov al, F6h
//out dx, al
//inc dx
//mov al, ?
//out dx, al
Out32(0x2E, 0xF6);
Out32(0x2F, ?&0xFF);
// ; lock chip
//dec dx
//mov al, AAh
//out dx, al
Out32(0x2E, 0xAA);

Сначала выполняется разблокировка чипа выполнением дважды инструкции 87h. Далее выбираются регистры WDT. Затем активируется функция таймера. После выбираются секунды в качестве единицы счета таймера и устанавливается значение интервала с одновременным запуском счетчика таймера. В конце чип блокируется.

За более подробной информацией лучше всего обращаться к исходникам и текстам примеров поставляемых в составе пакета Inpout32.