Справочник программиста на персональном компьютере фирмы IBM. Дисковые накопители - Чтение/запись определенных секторов

ОГЛАВЛЕНИЕ

     5.4.2 Чтение/запись определенных секторов.


   Чтение  или запись определенных секторов диска в основном  ис-
пользуется при доступе к каталогам диска или его таблице размеще-
ния  файлов, сектора для которых всегда расположены в одном и том
же месте.  В то время как чтение  секторов  достаточно безобидно,
запись абсолютного сектора требует чтобы код был тщательно прове-
рен перед первым использованием. Ошибка может сделать каталог или
таблицу размещения файлов нечитаемыми, что эквивалентно  разруше-
нию всех данных на диске.
   Как DOS так и BIOS  предоставляют  функции для чтения и записи
определенных  секторов.  Однако они указывают сектора по-разному.
Для IBM PC, XT и PCjr процедура BIOS  требует информации о номере
стороны (0 или 1), номере дорожки (0-39) и номере сектора  (1-8).
Из-за  ограничения  максимального  номера  сектора равного 8 этот
метод практически бесполезен для этих машин.  Однако для AT номер
сектора может меняться до  8,  9  или  15,  а число дорожек может
меняться до 39 или 79.  Функции DOS указывают сектор одним  номе-
ром, который называется  логическим  номером  сектора.  Начиная с
наружного  обода  диска, секторам  присваиваются  последовательно
возрастающие номера. Этот метод может быть использован для дисков
произвольного размера и типа.
   Отсчет  логисеких секторов начинается со стороны 0  дорожки  0
сектора 1 и продолжается  на  стороне  1  с дорожки 0, после чего
переходит на сторону 0 дорожку 1 и т.д. (На больших фиксированных
дисках сначала проходится весь внешний цилиндр.) В зависимости от
того как был форматирован диск, при переходе на следующую дорожку
логический номер сектора увеличивается на определенную  величину.
Для дискет емкостью 360K каждая  дорожка  (с учетом обеих сторон)
добавляет  к  логическому номеру 18.  Однако  вычисления  немного
усложняются тем, что  отсчет  начинается  с  нуля.  Таким образом
первый  сектор  на дорожке 3 стороны 2 должен иметь номер  равный
3*18 для дорожек 0-2 плюс 9 для стороны 0 дорожки 3 плюс единица,
указывающая на первый сектор дорожки 3 стороны 1. Эта сумма равна
64. Логический номер сектора на 1 меньше этого числа. На рис. 5-4
сравнивается методы указания сектора DOS и BIOS.

   Высокий уровень.


   Бейсик не предоставляет прямого доступа к секторам диска. Надо
использовать следующую процедуру на  машинном языке. В приложении
Г объясняется логика взаимодействия с этой процедурой.  В примере
читается 9 секторов дорожки  3  стороны  1 дискеты емкостью 360K.
Сама  процедура  размещается в памяти, начиная с адреса  сегмента
&H1000, а содержимое секторов размещается,  начиная с сегментного
адреса &H2000 (напоминаем, что абсолютный адрес равен сегментному
адресу, умноженному на 16).  Для  того чтобы записать на диск со-
держимое  этого  буфера надо изменить в данных программы  седьмой
байт с конца &H25 на &H26. Все остальное остается неизменным.

100 DEFINT A-Z       'все переменные будут целыми
110 DATA &H55, &H8B, &HEC, &H1E, &H8B, &H76, &H0C, &H8B
120 DATA &H04, &H8B, &H76, &H0A, &H8B, &H14, &H8B, &H76

130 DATA &H08, &H8B, &H0C, &H8B, &H76, &H06, &H8A, &H1C
140 DATA &H8E, &HD8, &H8B, &HC3, &H8B, &H00, &H00, &HCD
150 DATA &H25, &H59, &H1F, &H5D, &HCA, &H08, &H00

160 DEF SEG = &H1000     'помещаем процедуру по адресу &H10000
170 FOR N = 0 TO 38      'для каждого байта процедуры
180 READ Q: POKE N,Q     'читаем байт и помещаем его в память
190 NEXT                 'следующий байт
200 READSECTOR = 0       'выполняем код, начиная с первого байта
210 BUFFER = &H2000      'буфер для данных имеет адрес &H20000
220 LOGICALNUMBER = 62   'логический номер сектора равен 62
230 NSECTORS = 9         'число считываемых секторов
240 DRIVE = 0            'номер накопителя (0 = A)
250 CALL READSECTOR (BUFFER, LOGICALSECTORS, NSECTORS, DRIVE)
260 'теперь сектора в памяти, начиная с адреса 2000:0000

   Средний уровень.


   BIOS использует функцию 2 прерывания 13H для чтения секторов и
функцию 3 прерывания 13H для записи секторов.  В обоих случаях DL
должен содержать номер  накопителя  от 0 до 3, где 0 = A, 1 = B и
т.д.,  DH  - номер головки (стороны), 0-1.  CH  должен  содержать
номер дорожки от 0 до 39, а  CL  -  номер  сектора от 0 до 8.  AL
содержит число секторов, которое необходимо считать.  Допускается
сразу читать не более восьми  секторов,  что более чем достаточно
для большинства целей.  ES:BX должны указывать на начало буфера в
памяти, куда будут помещаться данные  или откуда они будут брать-
ся.   При возврате AL будет содержать число прочитанных или запи-
санных секторов.  Если операция  успешна,  то флаг переноса будет
равен  нулю.  Если он равен 1, то AH будет содержать байт статуса
дисковой операции, описанный в [5.4.8].

;---в сегменте данных
BUFFER     DB   4000 DUP(?)  ;создаем буфер

;---читаем сектора
   MOV  AX,SEG BUFFER       ;ES:BX должны указывать на буфер
   MOV  ES,AX               ;
   MOV  BX,OFFSET BUFFER    ;
   MOV  DL,0                ;номер накопителя
   MOV  DH,0                ;номер головки
   MOV  CH,0                ;номер дорожки
   MOV  CL,1                ;номер сектора
   MOV  AL,1                ;число секторов для чтения
   MOV  AH,2                ;номер функции чтения
   INT  13H                 ;

   Прерывания DOS 25H и 26H читают и записывают абсолютные секто-
ра диска, соответственно. Надо поместить логический номер старто-
вого сектора в DX, а DS:BX должны указывать на буфер. CX содержит
число  секторов для чтения или записи, а AL -  номер  накопителя,
где 0 = A, 1 = B  и  т.д.  Процедуры  портят  все регистры, кроме

сегментных. При возврате регистр флагов остается на стеке, остав-
ляя стек невыровненным.  Не  забудьте  вытолкнуть это значение со
стека  сразу после возврата (в примере это значение выталкивается
в CX).

;---в сегменте данных
BUFFER      DB  DUP 5000(?)   ;создаем буфер

;---читаем сектора
   PUSH DS                 ;сохраняем регистры
   MOV  AX,SEG BUFFER      ;DS:BX должны указывать на буфер
   MOV  DS,AX              ;
   MOV  BX,OFFSET BUFFER   ;
   MOV  DX,63              ;логический номер сектора
   MOV  CX,9               ;читаем всю дорожку
   MOV  AL,0               ;накопитель A
   INT  25H                ;функция чтения секторов
   POP  CX                 ;выталкиваем со стека флаги
   POP  DS                 ;восстанавливаем регистры
   JNC  NO_ERROR           ;если нет ошибки, то на продолжение
   CMP  AH,3               ;проверка возможных ошибок
    .
    .
NO_ERROR:                  ;продолжение программы

   Если при возврате флаг переноса равен 1, то произошла ошибка и
в этом случае AH и AL содержат два отдельных байта статуса  ошиб-
ки. Если AH = 4, то указанный сектор не найден, а если AH = 2, то
диск неверно отформатирован.  Если AH = 3, то была попытка записи
на дискету, защищенную от записи. Все остальные значения AH гово-
рят об аппаратной ошибке.

   Низкий уровень.


   Дисковые операции на низком уровне требуют прямого  программи-
рования микросхем  контроллера  НГМД  и прямого доступа к памяти.
Поскольку  эти  операции  взаимосвязаны, то  они  рассматриваются
вместе в разделе [5.4.1].