Суббота
18.05.2024
07:45
Форма входа
Категории раздела
Макроинструкции [3]
Управление данными [4]
Макросы [0]
ПК и железо [0]
Осиписание. :) [1]
Разное [4]
Поиск
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0

    OPEN SOURCE PROJECT

    Каталог статей

    Главная » Статьи » Осиписание. :)

    Fat 12 начальные сведенья
    Начнём…
    А начнём мы с того, что узнаем, какие данные нужно записать в загрузочный сектор (если он, конечно, есть) дискеты:

    Смещение Размер, байт Описание
    +3h 8 Аббревиатура и номер версии ОС
    +Bh 2 Число байт на сектор (512)
    +Dh 1 Число секторов на кластер
    +Eh 2 Число резервных секторов в резервной области раздела
    +10h 1 Число копий FAT в разделе (2)
    +11h 2 Количество 32-байтных дескрипторов файлов в корневом каталоге
    +13h 2 Общее число секторов в разделе
    +15h 1 Тип носителя информации (для современных дискет F0h)
    +16h 2 Количество секторов, занимаемых одной копией FAT
    +18h 2 Число секторов на дорожке
    +1Ah 2 Число головок
    +1Ch 4 Число скрытых секторов перед началом раздела (для дискет 0)
    +20h 4 0 (используется FAT32)
    +24h 1 Номер дисковода (для дискет - от 0 до 3)
    +25h 1 0 (для Windows NT)
    +26h 1 Признак расширенной загрузочной записи (29h)
    +27h 4 Номер логического диска (создается при форматировании)
    +2Bh 11 Метка диска (текстовая строка)
    +36h 8 Аббревиатура типа файловой системы
    +3Eh Начало загрузочного кода

    Загрузчик загружается по физическому адресу 07C00h размером 512 байт. Причём первые 3 байта программы придётся потратить на переход непосредственно к коду загрузчика ОС.

    Реализовать это можно следующим образом:


    .model tiny
    .code
    .286
    org 100h
    Start:

    jmp BeginJMP
    org 07C00h
    BeginJMP:
    jmp Begin
    gnOEM db "DATA " ; Аббревиатура и номер версии ОС
    gnSectSize dw 512 ; Число байт на сектор
    gnClustSize db 1 ; Число секторов на кластер
    gnRessect dw 1 ; Число резервных секторов
    gnFatCnt db 2 ; Число копий FAT
    gnRootSize dw 224 ; Размер корневой директории
    gnTotalSect dw 2880 ; Общее число секторов
    gnMedia db 0F0h ; Тип носителя информации
    gnFatSize dw 9 ; Количество секторов, занимаемых FAT
    gnTrackSect dw 18 ; Число секторов на дорожку
    gnHeadCnt dw 2 ; Число головок
    gnHidenSect dd 0 ; Число скрытых секторов
    gnHugeSect dd 0 ; Используется FAT32
    gnBootDrv db 0 ; Номер дисковода
    gnReserv db 0 ; Зарезервировано
    gnBootSign db 29h ; Признак расширенной загрузочной записи
    gnVolID dd 0 ; Номер логического диска
    gnVoLabel db "BASE " ; Метка диска
    gnFSType db "FAT12 " ; Аббревиатура типа файловой системы

    Begin:

    ; Загрузчик ОС

    Конечно это не самый идеальный вариант, т.к. приходится вырезать почти 07D00h байт от начала. Но главный плюс такого подхода – это простота. Я думаю, вам не составит труда смастерить утилиту для записи загрузочного сектора на дискету. Двигаемся дальше…

    Структура FAT.
    Первый байт таблицы FAT называется описателем устройства или FAT ID. Следующие пять байтов содержат 0FFh. Следующие байты состоят из 12 битных записей, которые описывают один кластер на диске. Для этих записей используются следующие значения:

    Значение Описание
    000h Свободный кластер.
    FF0h - FF6h Зарезервированный кластер.
    002h - FEFh Номер следующего кластера в цепочке
    FF7h Плохой кластер.
    FF8h-FFFh Последний кластер в цепочке.

    Следует учесть, что FAT находится в 1-ом кластере устройства, а корень в 19-ом, прошу не путать эти два понятия.
    Элементы оглавления.
    Что бы работать с файлами, нужно знать, где они хранятся, сколько байт занимают и т.д. Сейчас мы рассмотрим типичный элемент оглавления файла для FAT12:

    Смещение Длина, байт Содержимое
    +0 8 Имя файла (дополненное справа пробелами)
    +8 3 Расширение файла (дополненное справа пробелами)
    +0Bh 1 Атрибут файла:
    • 01h – Только чтение
    • 02h – Скрытый
    • 04h – Системный
    • 08h – Метка тома
    • 10h – Директория
    • 20h – Архив
    +0Ch 10 Зарезервировано
    +16h 2 Время создания или модификации в формате filetime
    +18h 2 Дата создания или модификации в формате filetime
    +1Ah 2 Номер начального кластера данных
    +1Ch 4 Размер

    Особое внимание нужно обратить на время и дату создания. Т.к. время и дата у нас в своём формате, имеет смысл описать алгоритм извлечения нормальных значений даты и времени:
    Считываем слово из элемента оглавления со смещением +16h. Поместим его в регистр AX. Для секундных единиц следует учесть, что 1 сек = 2 единицам.

    Секунды
    (0-30) Минуты
    (0-59) Часы
    (0-23)
    And AX, 001Fh
    Imul AX, 2
    AX = секунды And AX, 07E0h
    Shr AX, 5
    AX = минуты And AX, 0F800h
    Shr AX, 11
    AX = часы

    Для даты считываем слово из элемента оглавления со смещением +18h. Поместим его в регистр AX. После операций маскирования и сдвигов прибавьте к году 1980 (07BCh).

    День
    (0-31) Месяц
    (1-31) Год
    (0-119)
    And AX, 001Fh
    AX = день And AX, 01E0h
    Shr AX, 5
    AX = месяц And AX, 0FC00h
    Shr AX, 9
    Add AX, 07BCh
    AX = год

    Вот и всё что вам нужно знать об элементе оглавления файла. Но осталось самое главное, без чего мы не сможем работать с файлами.… Это, конечно же, работа с секторами и кластерами…

    Сектора и кластеры.
    И так дорогой друг, мы с тобой подошли к самому интересному в нашей работе. Если бы всё было так просто…. Взял, считал начальный кластер данных, а в конце кластера был бы записан следующий номер кластера и т.д. Но нет, мелкософт оказался умнее и предложил неплохую систему поиска и чтения кластеров - нахождение абсолютного сектора. Воспользуемся следующими обозначениями:
    N – кластер.
    Hidden - количество "скрытых" секторов (0)
    Reserved - количество резервных секторов (1)
    FATsize – размер одной копии FAT (9 секторов)
    FATCount – количество FAT’ов (2)
    RootSize - максимально возможное количество файловых записей в корневом каталоге (224)
    SectPerClust – количество секторов на кластер (512)

    Теперь для вычисления абсолютного сектора для кластера с номером N нам нужно будет воспользоваться формулами:

    Temp = Hidden + Reserved
    FATSect = FATCount * FATsize
    RootData = (RootSize*32 + (SectPerClust-1)) / SectPerClust
    SectOffset = (N -2)* SectPerClust
    AbsSect = Temp + FATSect + RootData + SectOffset

    Абсолютный номер первого сектора для кластера с номером N это и есть AbsSect. Теперь мы свободно можем использовать номер этого сектора для работы с прерыванием INT 13h, нужно только рассчитать головку и дорожку.
    Для чтения кластера в определённую область памяти можно воспользоваться вот такой процедурой:

    push di
    push es
    ; Начало расчета сектора/дорожки/головки
    push cs
    pop ds
    mov cx,[gnTrackSect] ; Количество секторов на дорожку
    mov si,dx
    ; tmp=(Sector/TrackSectors);
    mov ax,si
    xor dx,dx
    div cx
    mov di,ax
    ; Sec=Sector-(tmp*TrackSectors)+1;
    mov ax,di
    imul cx
    mov dx,si
    sub dx,ax
    inc dx
    mov [AbsSectNum],dx
    ; Head=tmp & 1;
    mov ax,di
    and ax,1
    mov [AbsHeadNum],ax
    ; Trk=(Sector-(Head*TrackSectors)-(Sec-1))/(TrackSectors*2);
    imul cx
    push ax
    mov ax,si
    pop dx
    sub ax,dx
    mov dx,[AbsSectNum]
    dec dx
    sub ax,dx
    mov dx,cx
    shl dx,1
    push ax
    push dx
    xor dx,dx
    pop bx
    pop ax
    div bx ; AX = AbsTrackNum
    ; Конец расчетов
    mov cx,ax
    mov al,cl
    shr cx,2
    and cl,0C0h
    mov ch,al
    and cx,0FFC0h
    mov ax,[AbsSectNum]
    or cl,al
    pop es
    pop bx ; ES:BX = Куда считывать
    mov dx,[AbsHeadNum]
    mov dh,dl ; Номер головки
    mov dl,00h ; Номер диска 0 = A
    xor dl,dl
    mov al,1 ; Количество считываемых секторов
    mov ah,2 ; Номер функции
    int 13h

    Эта процедура взята из системы Gluk OS. Т.к. система была, что называется Open Source, то думаю, ничего противозаконного в публикации её здесь нет. Здесь и далее мы будем пользоваться именно этой процедурой. На самом деле вся дальнейшая работа по чтению FAT строится именно на этой процедуре, поэтому удостоверьтесь, что вы написали её правильно.
    Это конечно замечательно, что мы можем читать первый кластер файла, но что делать, если файл больше 512 байт?
    Ответ прост, обратимся к докам мелкософта. А там сказано, что для того, чтобы прочесть значение любой записи FAT (значение будет равно следующей записи в
    цепочке), необходимо сначала прочесть всю таблицу FAT в память, а затем получить номер первого кластера файла. После того как мы получили первый кластер файла нам нужно совершить кое-какие действия для получения следующей записи в
    цепочке:
    • Умножить номер кластера на 3
    • Разделить результат на 2 (каждое значение 12 бит = 1,5 байта, а результат 3 / 2 = 1,5)
    • Считать слово (WORD) из полученного адреса (как смещение от начала FAT)
    • Если кластер с четным номером, то наложить маску 0FFFh (сохранить нижние 12 бит)
    Если кластер нечетный, то сдвинуть значение на 4 бита вправо (сохранить верхние 12 бит)
    • Результатом будет номер следующего кластера в цепочке (если 0FFFh, то это последний)

    Замечательно! Вот и ответ на наш вопрос. Осталось только это реализовать:

    Start_read_next:
    push dx
    push di
    push es
    add dx,31 ;Преобразуем в номер сектора
    Call ReadSect ;Чтение сектора
    pop es
    pop di
    pop dx
    ;Получить следующий сектор после DX
    push di
    mov di,offset Mem_FAT
    mov ax,dx
    mov bx,ax
    mov cx,3
    mul cx
    shr ax,1
    add di,ax
    mov dx,word ptr es:[di]
    and bx,1
    je gns01 ;Если номер кластера четный
    shr dx,4
    jmp gns02
    gns01:
    and dx,0FFFh
    gns02:
    pop di
    cmp dx,0FFFh
    je End_Begin ;FFF - последний кластер
    add di,512
    jmp Start_read_next
    End_Begin:

    Осталась самая малость – написать программу для чтения FAT и рута за одно. Идём далее…

    Читаем FAT.
    Вот, наконец, программа для чтения FAT и рута с диска A:\ в определённые области памяти. Собирается в TASM 5.0 как обычный COM файл. С компоновкой и сборкой у вас не должно возникнуть проблем.

    .model tiny
    .code
    .386p
    org 100h
    start:
    mov ax,0003h
    int 10h
    call ReadRootDir
    call ReadFAT
    ret

    ; Чтение сектора (DX=номер сектора)
    ; ES:DI – Адрес для приёма данных

    ReadSect proc
    push di
    push es
    ; Начало расчета сектора/дорожки/головки
    push cs
    pop ds
    mov cx,[gnTrackSect]
    mov si,dx
    ; tmp=(Sector/TrackSectors);
    mov ax,si
    xor dx,dx
    div cx
    mov di,ax
    ; Sec=Sector-(tmp*TrackSectors)+1;
    mov ax,di
    imul cx
    mov dx,si
    sub dx,ax
    inc dx
    mov [AbsSectNum],dx
    ; Head=tmp & 1;
    mov ax,di
    and ax,1
    mov [AbsHeadNum],ax
    ; Trk=(Sector-(Head*TrackSectors)-(Sec-1))/(TrackSectors*2);
    imul cx
    push ax
    mov ax,si
    pop dx
    sub ax,dx
    mov dx,[AbsSectNum]
    dec dx
    sub ax,dx
    mov dx,cx
    shl dx,1
    push ax
    push dx
    xor dx,dx
    pop bx
    pop ax
    div bx ; AX = AbsTrackNum
    ; Конец расчетов
    mov cx,ax
    mov al,cl
    shr cx,2
    and cl,0C0h
    mov ch,al
    and cx,0FFC0h
    mov ax,[AbsSectNum]
    or cl,al
    pop es
    pop bx ; ES:BX = Куда считывать
    mov dx,[AbsHeadNum]
    mov dh,dl ; Номер головки
    mov dl,0 ; Номер диска 0 = A
    mov al,1 ; Количество считываемых секторов
    mov ah,2 ; Номер функции
    int 13h
    ret
    ReadSect endp

    ReadRootDir proc
    ;Чтение корневого каталога в оперативную память
    pusha
    mov dx,19 ;Начальный сектор ROOT′a
    mov di,offset RootDir
    Cont_Read_Root:
    push dx
    push di
    push es
    Call ReadSect ;Чтение сектора
    pop es
    pop di
    pop dx
    add di,512
    inc dx
    cmp dx,33
    jne Cont_Read_Root
    popa
    ret
    ReadRootDir endp


    ReadFAT proc
    ;Чтение таблицы размещения файлов в оперативную память
    pusha
    mov dx,1
    mov di,offset Mem_FAT
    Cont_Read_Fat:
    push dx
    push di
    push es
    Call ReadSect
    pop es
    pop di
    pop dx
    add di,512
    inc dx
    cmp dx,10
    jne Cont_Read_Fat
    popa
    ret
    ReadFAT endp

    AbsSectNum dw 0
    AbsHeadNum dw 0
    gnTrackSect dw 18 ; Число секторов на дорожку
    Mem_FAT db 9*512 dup(?)
    RootDir db 15*512 dup (?)
    end start


    Вот вы и познакомились с основами работы в FAT12. Надеюсь, что вам эта статья хоть чуть-чуть, но помогла. Т.к. человеку свойственно ошибаться, то шлите все ругательства, просьбы, и замечания на мыло: Exs42@yandex.ru. Отдельное и большое спасибо: Xbyte и Mirzman за кодерскую помощь! Спасибо за внимание, всем удачи!
    К началу статьи

    Категория: Осиписание. :) | Добавил: fasm (19.07.2008)
    Просмотров: 1873 | Рейтинг: 0.0/0
    Всего комментариев: 0
    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]