Работа с жестким диском на программном уровне::Журнал СА 9.2003
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

Книжная полка  

От создания сайтов до разработки и реализации API

В издательстве «БХВ» недавно вышли книги, которые будут интересны системным администраторам, создателям

 Читать далее...

Разбор полетов  

Ошибок опыт трудный

Как часто мы легко повторяем, что не надо бояться совершать ошибки, мол,

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6143
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 6856
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4139
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 2978
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3781
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3789
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6283
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3134
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3434
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7246
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10616
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12336
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 13969
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9100
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7053
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5362
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4594
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3402
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3129
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3379
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3000
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Работа с жестким диском на программном уровне

Архив номеров / 2003 / Выпуск №9 (10) / Работа с жестким диском на программном уровне

Рубрика: Администрирование /  Оборудование

ВЛАДИМИР МЕШКОВ

Работа с жестким диском на программном уровне

В номере 3(4) журнала «Системный администратор» была опубликована статья Алексея Серебрякова «Основы систем хранения данных». В продолжение данной темы давайте рассмотрим, как осуществить доступ к IDE-диску на программном уровне при помощи файла устройства и через порты ATA-контроллера.

Файлы устройств

Файл – основа любой операционной системы, поскольку именно с ним производится наибольшее число действий. В UNIX- и POSIX-системах существуют файлы следующих типов:

  • обычный файл;
  • каталог;
  • FIFO-файл;
  • байт-ориентированный файл устройства;
  • блок-ориентированный файл устройства.

Блок-ориентированный файл устройства служит для представления физического устройства, которое передает данные блоками. Примером блок-ориентированного устройства является жесткий диск. Байт-ориентированный файл устройства служит для представления физического устройства, которое передает данные побайтово (например, модем). Прикладная программа может выполнять операции чтения и записи с файлом устройства так же, как с обычным файлом, а операционная система будет автоматически вызывать соответствующий драйвер устройства для выполнения фактической передачи данных между физическим устройством и приложением. Файл устройства создается командой mknod, одним из аргументов которой является старший номер устройства (major device number). По сути, старший номер – это индекс в таблице ядра, которая содержит адреса всех драйверов, известных системе. В ОС Linux создаются две таблицы – таблица блочных устройств (block device switch) и таблица символьных устройств (character device switch). Обе таблицы являются массивом структур и проиндексированы при помощи значения старшего номера устройства. Таблица блочных устройств определена в файле fs/block_dev.c следующим образом:

static struct {

    const char *name;

    struct block_device_operations *bdops;

} blkdevs[MAX_BLKDEV];

Этот массив заполняется во время регистрации блочного устройства в системе. Для регистрации устройства соответствующий драйвер вызывает функцию register_blkdev (см. файл fs/block_dev.c):

int register_blkdev(unsigned int major, const char * name, struct block_device_operations *bdops)

{

    ....

    blkdevs[major].name = name;

    blkdevs[major].bdops = bdops;

    return 0;

}

Аргумент major – старший номер устройства, name – имя файла устройства, структура struct block_device_operations содержит функции, выполняемые драйвером устройства. Однако функции read и write в этой структуре отсутствуют. Дело в том, что пользовательский процесс не выполняет напрямую операции чтения/записи в блочное устройство. Для этой цели драйвер предоставляет системе механизм request, и все операции ввода/вывода выполняются через буферный кеш системы, но это тема для отдельной статьи.

При снятии регистрации соответствующий элемент массива blkdevs обнуляется:

int unregister_blkdev(unsigned int major, const char * name)

{

    ....

    blkdevs[major].name = NULL;

    blkdevs[major].bdops = NULL;

    return 0;

}

Таблица символьных устройств определена в файле fs/devices.c и также является массивом структур, который заполняется при регистрации устройства в системе:

struct device_struct {

    const char * name;

    struct file_operations * fops;

};

static struct device_struct chrdevs[MAX_CHRDEV];

Структура struct file_operations определена в файле и содержит функции, выполняемые драйвером символьного устройства.

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

Кроме операций чтения/записи драйвер также предоставляет возможность управления устройством. Операция управления осуществляется при помощи функции ioctl. Эта функция вызывается пользовательским процессом и имеет следующий прототип:

    int ioctl(int fd, int cmd, ...);

Аргументы функции: int fd – файловый дескриптор устройства; int cmd – команда, посылаемая устройству. Третий параметр является специфичным для каждого устройства, поэтому в прототипе функции не указан.

Доступ к жесткому диску через файл устройства

Предположим, что в системе присутствует один накопитель на  жестком магнитном диске, который подключен как Primary Master. Согласно обозначениям блочных устройств, принятым в ОС Linux, ему соответствует файл устройства /dev/hda. Разработаем программный модуль, выполняющий чтение первого сектора (MBR) и получающий информацию об устройстве, такой, как модель жесткого диска, его серийный номер, геометрию (число цилиндров/головок/секторов) и число логических блоков.

Нам понадобятся следующие заголовочные файлы:

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/types.h>

#include <errno.h>

#include <linux/hdreg.h>

В файле <linux/hdreg.h> определена структура struct hd_driveid, предназначенная для хранения информации идентификации устройства, и перечень команд управления устройством.

int main()

{

    struct hd_driveid ide;

    int hda, sect;

    char sector[512];

Для доступа к устройству достаточно стандартным способом открыть соответствующий файл устройства:

    hda=open("/dev/hda",O_RDONLY);

    if(!hda) {

           perror("hda");

    }

    sect=open("mbr",O_CREAT|O_RDWR,0600);

    if(!sect) {

           perror("sect");

    }

Для получения информации идентификации устройства посылаем команду HDIO_GET_IDENTITY. Команда идентификации позволяет считать из контроллера блок из 256 слов, характеризующих устройство. Результат будет сохранен в структуре struct hd_driveid ide, адрес которой задается в качестве третьего аргумента функции ioctl:

    if(ioctl(hda,HDIO_GET_IDENTITY,&ide)) perror ("HDIO_GET_IDENTITY");

Как уже было упомянуто, перечень команд управления устройством определен в файле <linux/hdreg.h>. Например, команды включения 32-битного режима обмена данными, режима DMA и мультисекторного чтения выглядят следующим образом:

    static u_long dma=1, io32set=1, mult=16;

    if(ioctl(hda,HDIO_SET_32BIT,io32set)) perror("HDIO_SET_32BIT");

    if(ioctl(hda,HDIO_SET_DMA,dma)) perror("HDIO_SET_DMA");

    if(ioctl(hda,HDIO_SET_MULTCOUNT,mult)) perror("HDIO_SET_MULTCOUNT");

Отобразим информацию идентификации устройства:

    printf("Серийный номер – %s\n",ide.serial_no);

    printf("Модель – %s\n",ide.model);

    printf("Число логических блоков – %d\n",ide.lba_capacity);

    printf("Число цилиндров – %d\n",ide.cyls);

    printf("Число головок – %d\n",ide.heads);

    printf("Число секторов – %d\n",ide.sectors);

Считываем первый сектор и сохраняем его в отдельном файле:

    read(hda,sector,sizeof(sector));

    write(sect,sector,sizeof(sector));

    close(hda);

    close(sect);

    return (0);

}

Как вы видите, доступ к жесткому диску через файл устройства наиболее простой и удобный, т.к. позволяет абстрагироваться от деталей функционирования устройства.

Давайте теперь посмотрим на жесткий диск с точки зрения драйвера, но в начале – немного теории.

Интерфейс АТА

Ниже приведены краткие сведения об интерфейсе АТА-2. Для получения детальной информации обратитесь к спецификации.

Регистры АТА-контроллера

Каждое устройство АТА (жесткий диск с интерфейсом АТА) имеет стандартный набор регистров, адресуемых сигналами от хост-адаптера (средства сопряжения интерфейса АТА с системной шиной). Набор регистров состоит из двух блоков – блока командных регистров и блока управляющих регистров.

Блок командных регистров служит для посылки команд устройству и передачи информации о его состоянии. Состав блока командных регистров:

  • Регистр состояния/команд – в режиме чтения отражает текущее состояние устройства в процессе выполнения команды. Чтение регистра состояния разрешает дальнейшее изменение его бит и сбрасывает запрос аппаратного прерывания. В режиме записи принимает коды команд для выполнения. Назначение бит регистра состояния:
    • Бит 7 – BSY (Busy) указывает на занятость устройства. При единичном значении устройство игнорирует попытки записи в блок командных регистров. При нулевом значении этого бита регистры командного блока доступны. Бит устанавливается под действием аппаратного или программного сброса, а также при получении команды.
    • Бит 6 – DRDY (Device Ready) указывает на готовность устройства к восприятию любых кодов команд.
    • Бит 5 – DF (Device Fault) – индикатор отказа устройства.
    • Бит 4 – DSC (Device Seek Complite) – индикатор завершения поиска трека.
    • Бит 3 – DRQ (Data Request) – индикатор готовности к обмену словом или байтом данных.
    • Бит 2 – CORR (Correct Data) – индикатор исправленной ошибки данных.
    • Бит 1 – IDX (Index) – индекс трактуется специфично для каждого производителя. Бит 0 – ERR (Error) – индикатор ошибки  выполнения предыдущей операции. Дополнительная информация содержится в регистре ошибок.
  • Регистр номера цилиндра (старшего и младшего байта) и номера сектора имеют двоякое назначение в зависимости от выбранной системы адресации (CHS или LBA). Они инициализируются хост-адаптером, а в случае возникновения ошибки при операции устройство поместит в них адрес, по которому встретилась ошибка.
  • Регистр номера устройства и головки, кроме хранения части адресной информации, служит для выбора ведущего или ведомого устройства (Device-0 и Device-1 согласно спецификации ATA) и метода адресации.
    • Биты 7 и 5 – зарезервированы.
    • Бит 6 – единичным значением указывает на применение режима адресации LBA. При нулевом значении бита используется режим CHS.
    • Бит 4 – DEV (Device) – выбор устройства. При DEV=0 выбрано устройство-0 (Master), при DEV=1 – устройство-1 (Slave).
    • Биты 3-0 имеют двоякое назначение, в зависимости от выбранной системы адресации. В режиме CHS они содержат номер головки, в режиме LBA – старшие биты логического адреса.
  • Регистр данных может использоваться как 8-битный и 16-битный, в зависимости от типа данных, передаваемых в текущей команде.
  • Регистр ошибок хранит состояние выполнения последней операции или диагностический код.
  • Регистр свойств (Features Register) используется в зависимости от команды.
  • Регистр счетчика секторов содержит число секторов, участвующих в обмене. Нулевое значение соответствует 256 секторам.

Блок управляющих регистров используется для управления устройством и получения байта его состояния. В состав блока входят альтернативный регистр состояния и регистр управления устройством. Альтернативный регистр состояния имеет те же биты, что и основной, но его чтение не приводит ни к каким изменениям состояния устройства.

В регистре управления устройством биты 7-3 зарезервированы, бит 0 всегда нулевой, используются только два бита:

  • Бит 2 – SRST (Software Reset) – программный сброс действует все время, пока бит не будет сброшен. Оба устройства шины воспринимают программный сброс одновременно.
  • Бит 1 – IEN# (Interrupt Enable) – инверсный бит разрешения прерывания.

Адреса регистров контроллера устройства 0 определены в файле :

#define HD_DATA         0x1f0  /* регистр данных */

#define HD_ERROR        0x1f1  /* регистр ошибок */      

#define HD_NSECTOR      0x1f2  /* регистр счетчика секторов */

#define HD_SECTOR       0x1f3  /* регистр стартового сектора */

*/#define HD_LCYL       0x1f4  /* регистр младшего байта номера цилиндра */  

#define HD_HCY          0x1f5  /* регистр старшего байта номера цилиндра */

#define HD_CURRENT      0x1f6  /* 101dhhhh, d=устройство, hhhh=головка */

#define HD_STATUS       0x1f7  /* регистр состояния/команд */

Протокол взаимодействия

    Обычный протокол взаимодействия хоста с устройством выглядит следующим образом:

  1. Хост читает регистр состояния устройства, дожидаясь нулевого значения бита BSY.
  2. Дождавшись освобождения устройства, хост записывает в регистр номера устройства и головки байт, у которого бит DEV указывает на адресуемое устройство.
  3. Хост читает основной регистр состояния адресованного устройства, дожидаясь признака его готовности (DRDY = 1).
  4. Хост заносит требуемые параметры в блок командных регистров.
  5. Хост записывает код команды в регистр команд.
  6. Устройство устанавливает бит BSY и переходит к исполнению команды.
  7. Для команд, не требующих передачи данных (ND):

  8. Завершив исполнение команды, устройство сбрасывает бит BSY и устанавливает запрос прерывания. К этому моменту в регистрах состояния и ошибок уже имеется информация о результате выполнения.
  9. Для команд, требующих чтения данных в режиме PIO:

  10. Подготовившись к передаче первого блока данных по шине АТА, устройство устанавливает бит DRQ. Если была ошибка, она фиксируется в регистрах состояния и ошибок. Далее устройство сбрасывает бит BSY и устанавливает запрос прерывания.
  11. Зафиксировав обнуление бита BSY (или по прерыванию), хост считывает регистр состояния, что приводит к сбросу прерывания от устройства.
  12. Если хост обнаружил единичное значение бита DRQ, он производит чтение первого блока данных в режиме PIO (адресуясь к регистру данных). Если обнаружена ошибка, считанные данные могут быть недостоверными.
  13. После передачи блока данных возможно одно из следующих действий:

  • если на шаге 8 ошибка не обнаружена, а требуется передача следующего блока, устройство устанавливает бит BSY, и данная последовательность повторяется с шага 7.
  • если есть ошибка или передан последний блок данных, устройство сбрасывает бит DRQ и выполнение команды завершается.

Операцию записи на жесткий диск рассматривать не будем.

Доступ к жесткому диску через порты АТА-контроллера

Задача прежняя – получить информацию идентификации устройства и считать MBR. Рассмотрим программный код.

Заголовочные файлы:

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <linux/hdreg.h>

Для работы с портами ввода/вывода определим несколько макросов:

#define OUT_P_B(val,port)      \

    asm(                       \

           "outb %%al, %%dx"   \

           ::"a"(val),"d"(port)\

    )

#define IN_P_B(val,port)       \

    asm(                       \

           "inb %%dx, %%al"    \

           :"=a"(val)          \

           :"d"(port)          \

    )

#define IN_P_W(val,port)       \

    asm(                       \

           "inw %%dx, %%ax"    \

           :"=a"(val)          \

           :"d"(port)          \

    )

Макрос OUT_P_B осуществляет запись байта в порт, макросы IN_P_B и IN_P_W – чтения байта/слова из порта.

Для работы с устройством определим несколько функций.

Функция проверки статуса устройства (занято/свободно):

void hd_busy()

{

    unsigned char status;

    do {

           IN_P_B(status,HD_STATUS);

    } while (status & 0x80);

    return;

}

Проверка статуса устройства осуществляется проверкой значения бита 7 (BSY) регистра состояния. Если бит сброшен, устройство свободно и регистры контроллера доступны.

Функция проверки готовности устройства к восприятию команд:

void hd_ready()

{

    unsigned char status;

    do {

           IN_P_B(status,HD_STATUS);

    } while (!(status & 0x40));

    return;

}

Устройство готово, если бит 6 (DRDY) регистра состояния установлен.

Функция проверки готовности устройства к обмену данными:

int hd_data_request()

{

    unsigned char status;

    IN_P_B(status,HD_STATUS);

    if(status & 0x8) return 1;

    return 0;

}

Если бит 3 (DRQ) регистра состояния установлен, данные находятся в регистре данных и готовы для считывания.

Следующая функция проверяет, не произошла ли ошибка при работе устройства:

void check_error()

{

    unsigned char a;

    IN_P_B(a,HD_STATUS);

    if (a & 0x1) {

           perror("HD_STATUS");

           exit(-1);

    }

    return;

}

Установленный бит 0 (ERR) регистра состояния означает, что при выполнении последней операции произошла ошибка. Дополнительная информация содержится в регистре ошибок.

А теперь рассмотрим функцию получения информации идентификации устройства.

void get_hd_identity(struct hd_driveid *hd)

{

    unsigned short a = 0;

    int i = 0;

    unsigned short buff1[0x100];

    memset(buff1,0,0x100);

В соответствии с протоколом взаимодействия проверяем статус устройства. Оно должно быть свободно:

    hd_busy();

Как только устройство освободилось, в регистр номера устройства и головки заносим значение 0xA0 (10100000 в двоичном виде). Бит 4 (DEV) равен 0, следовательно, нами выбрано ведущее устройство. Режим адресации в данном случае роли не играет, бит 6 оставим нулевым:

    OUT_P_B(0xA0,HD_CURRENT);

Ожидаем готовность устройства к восприятию команд:

    hd_ready();

Итак, устройство готово. В регистр команд (HD_STATUS) записываем код команды идентификации устройства – 0xEC. Данная команда выполняется в режиме PIO. Полный перечень команд смотрите в спецификации:

    OUT_P_B(0xEC,HD_STATUS);

В ответ на эту команду устройство установит бит DRQ и вернет блок данных, содержащих информацию идентификации. Для считывания информации организуем цикл:

    do {

           hd_busy();

           check_error();

           IN_P_W(a,HD_DATA);

           if((i>=10 && i<=19) || (i>=27 && i<=46))

           asm(

                 "xchgb %%ah, %%al"

                 :"=a"(a)

                 :"0"(a));

           buff1[i++] = a;

    } while(hd_data_request());

Дождавшись освобождения устройства, при помощи функции check_error() читаем регистр состояния. При этом мы сбрасываем прерывание от устройства и проверяем, не произошла ли ошибка. Затем считываем из регистра данных значение. Считывание производим до тех пор, пока установлен бит DRQ. Как только будет передан последний блок данных, устройство этот бит сбросит. Считанную информацию сохраним в буфере buff1.

Копируем полученную информацию из буфера buff1 в структуру struct hdreg hd:

    memcpy(hd,(struct hdreg *)buff1,0x100);

Очищаем буфер и выходим:

    memset(buff1,0,0x100);

    return;

}

Следующая функция осуществляет чтение сектора в режиме адресации CHS.

void read_hd_sector_chs(unsigned short N, unsigned short s_sect, unsigned short s_cyl, unsigned short head, unsigned short *buff)

{

    int i = 0;

    unsigned short a;

    if((!N) || (!s_sect)) return;

Аргументы функции:

  • N – число секторов для чтения;
  • s_sect – стартовый сектор;
  • s_cyl – стартовый цилиндр;
  • head – номер головки;
  • buff – буфер, куда все помещается.

Ожидаем освобождения устройства:

    hd_busy();

В регистр номера устройства и головки заносим соответствующие данные. Бит 6 сброшен, что указывает на режим адресации CHS:

    OUT_P_B(0xA0|head,HD_CURRENT);

Ждем готовность устройства к приему команд:

    hd_ready();

В блок командных регистров заносим требуемые параметры:

    OUT_P_B(N,HD_NSECTOR);

    OUT_P_B(s_sect,HD_SECTOR);

    OUT_P_B(s_cyl,HD_LCYL);

    OUT_P_B((s_cyl >> 8),HD_HCYL);

В регистр команд записываем код команды чтения секторов с повторами – 0x20. Данная команда выполняется в режиме PIO:

    OUT_P_B(0x20,HD_STATUS);

Считываем блок данных в буфер buff:

    do {

           hd_busy();

           check_error();

           IN_P_W(a,HD_DATA);

           buff[i++] = a;

    } while(hd_data_request());

Считываем последние 4 байта и выходим из функции:

    IN_P_W(a,HD_DATA);

    buff[i++] = a;

    IN_P_W(a,HD_DATA);

    buff[i] = a;

    return;

}

Функция чтения сектора в режиме адресации LBA.

void read_hd_sector_lba(unsigned short N, unsigned int lba, unsigned short *buff)

{

    int i = 0;

    unsigned short a;

    if(!N) return;

Аргументы функции:

  • N – число секторов для чтения;
  • lba – номер блока;
  • buff – буфер, куда все помещается.

Ожидаем освобождения устройства:

    hd_busy();

Спецификацией АТА-2 в режиме LBA предусмотрен 28-битный адрес сектора размером 512 байт, при этом максимальный объем ограничивается значением 0,5 терабайт.

В регистре номера устройства и головки бит 6 устанавливаем в 1, а биты 3-0 будут содержать старшие биты логического адреса (27-24):

    OUT_P_B(0xE0|((lba & 0x0F000000) >> 24),HD_CURRENT);

Ожидаем готовность устройства к приему команд:

    hd_ready();

В блок командных регистров заносим требуемые параметры:

    OUT_P_B(N,HD_NSECTOR);

В регистр номера сектора заносим биты 7-0 логического адреса:

    OUT_P_B((lba & 0x000000FF),HD_SECTOR);

В регистр младшего байта номера цилиндра – биты 15-8 логического адреса:

   OUT_P_B(((lba & 0x0000FF00) >> 8),HD_LCYL);

В регистр старшего байта номера цилиндра – биты 23-16 логического адреса:

    OUT_P_B(((lba & 0x00FF0000) >> 16),HD_HCYL);

В регистр команд – команду чтения секторов с повторами:

    OUT_P_B(0x20,HD_STATUS);

Получаем результат:

    do {

           hd_busy();

           check_error();

           IN_P_W(a,HD_DATA);

           buff[i++] = a;

    } while(hd_data_request());

Считываем последние 4 байта и выходим:

    IN_P_W(a,HD_DATA);

    buff[i++] = a;

    IN_P_W(a,HD_DATA);

    buff[i] = a;

    return;

}

Рассмотрим главную функцию:

int main ()

{

Определим необходимые структуры и  переменные:

    struct hd_driveid hd;

    int out;

    unsigned short N = 1;

    unsigned int sect, cyl, head, lba;

/*

 * N – число секторов для чтения

 * sect – номер сектора

 * cyl – номер цилиндра

 * head – номер головки

 * lba – номер логического блока

 */

    unsigned short buff[0x100*N];

    memset(buff,0,0x100*N);

    memset(&hd,0,sizeof(struct hd_driveid));

Чтобы не схлопотать Segmentation fault, запросим у системы разрешение доступа к портам в диапазоне 0x1f0 – 0x1f7:

    ioperm(0x1f0,8,1);

Вызовем функцию получения информации идентификации. Результат будет помещен в структуру struct hd_driveid hd:

    get_hd_identity(&hd);

Отобразим результаты:

    printf("Серийный номер – %s ",hd.serial_no);

    printf("Модель – %s ",hd.model);

    printf("Число цилиндров - %d ",hd.cur_cyls);

    printf("Число головок – %d ",hd.cur_heads);

    printf("Число секторов – %d ",hd.cur_sectors);

    printf("Число логических блоков – %d ",hd.lba_capacity);

А теперь прочитаем первый сектор устройства (MBR) в режиме CHS:

    sect = 1;

    cyl = 0;

    head = 0;

    read_hd_sector_chs(N,sect,cyl,head,buff);

Запишем в файл результат:

    out=open("sect_chs", O_CREAT|O_RDWR, 0600);

    write(out,(unsigned char *)buff,0x200*N);

    close(out);

То же самое – в режиме LBA:

    lba = 0;

    read_hd_sector_lba(N,lba,buff);

    out=open("sect_lba", O_CREAT|O_RDWR, 0600);

    write(out,(unsigned char *)buff,0x200*N);

    close(out);

    ioperm(0x1f0,8,0);

    return (0);

}

Весь вышеприведенный код сохраним в файле disk.c. Исполняемый модуль получим, введя команду:

    gcc -o disk disk.c

Работоспособность кода была проверена для ОС Linux, версия ядра 2.4.20.

Как вы понимаете, рассмотреть в рамках одной статьи всю систему команд стандарта АТА не представляется возможным, да мы и не ставили перед собой такую цель. Желающие могут продолжить освоение данной темы, изучив спецификацию и систему команд стандарта АТА либо исходные тексты утилиты hdparm

Литература:

  1. Теренс Чан. Системное программирование на С++ для UNIX. Пер. с англ. – К.: Издательская группа BHV, 1999. – 592 с.
  2. Гук. М. Интерфейсы ПК: справочник – СПб: Питер Ком, 1999. – 416 с.

Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru