cmp bx, max_root_entries ; Have we gone through all root entries?
mov al, sectors_fat ; Read all sectors in FAT
mov al, sectors_cluster ; Read the number of sectors in 1 cluster
Все вышеперечисленное неверно. Вы используете NASM, и поэтому вам нужно написать квадратные скобки, чтобы извлечь что-то из памяти. Без скобок вы получаете сам адрес, а не содержание.
cmp bx, [bpbRootEntries]
...
В спецификации моей файловой системы FAT упоминается:
Нет такой вещи, как том FAT16, который имеет менее 4085 кластеров ...
... Если вы попытаетесь создать том FAT, который нарушает это правило, операционные системы Microsoft не будут правильно их обрабатывать, поскольку они будут думать, что том имеет тип FAT, отличный от того, который, как вы думаете, делает.
Используемый диск имеет 2880 секторов и, следовательно, слишком мало кластеров для распознавания как FAT16. Возможно, ваша операционная система Linux распознает это нормально, но, возможно, ваша команда mount
должна использовать такую опцию, как fat=16
.
Те же 2880 секторов и, учитывая, что bpbSectorsPerCluster = 0x01, потребуют, чтобы FAT составляли каждые 12 секторов. Тем не менее, я вижу, что bpbFATSize16 = 0x0009 - это значение, которое я бы ожидал для FAT 12 .
Структура Boot Sector и BPB содержит много информации, которую ваша программа должна использовать вместо того, чтобы полагаться на константы, которые вы не смогли правильно инициализировать. Однако в своем ответе я буду продолжать использовать эти (исправленные) константы для простоты!
FirstFATSecNum = bpbHiddenSectors + bpbReservedSectors
= 0x00000000 + 0x0001
= 1
FirstRootDirSecNum = FirstFATSecNum + bpbNumberOfFATs * bpbFATSize16
= 1 + 0x02 * 0x0009
= 19
RootDirSectors = ((bpbRootEntries * 32) + (bpbBytesPerSector - 1)) / bpbBytesPerSector
= ((0x0200 * 32) + (0x200 - 1)) / 0x200
= 32
FirstDataSecNum = FirstRootDirSecNum + RootDirSectors
= 19 + 32
= 51
Важно видеть, что RootDir занимает 32 сектора или 16384 байта! Ваша программа настроила DiskBuffer размером всего 8192 байта. Это было основано на вашем неверном предположении, что RootDir содержит 224 записи, нормальное число для FAT 12 .
Процедура, которая преобразует номер логического сектора, может быть более точно названа "SetupCHS". Это лучше выражает то, что он делает больше, чем простое преобразование, а также подчеркивает относительную значимость между Цилиндром, Головкой и Сектором. например Сравните это с HMS по часам, минутам и секундам. Итак, переходя от наиболее значимого (C) к наименее значимому (S).
; IN (ax) OUT (cx,dx) MOD (ax)
SetupCHS:
cwd
div word [bpbSectorsPerTrack]
mov cl, dl
inc cx ; Sector number
cwd
div word [bpbNumberOfHeads]
mov dh, dl ; Head number
mov ch, al ; Cylinder number
mov dl, [drive_num] ; Drive number
ret
Для ясности не следует устанавливать здесь номер функции в AH
, но рядом с тем местом, где у вас есть инструкция int 0x13
!
Многие BIOS не могут читать / записывать несколько секторов одновременно, особенно если им приходится пересекать какую-то границу, будь то другая головка или другой цилиндр.
Вот почему большинство предусмотрительных программистов будут использовать цикл 1-секторного чтения / записи.
; Loading the RootDir
mov bx, DiskBuffer ; ES:BX
mov ax, 19 ; FirstRootDirSecNum
call SetupCHS ; -> CX DX (AX)
mov bp, 32 ; RootDirSectors
.Next:
call ReadOneSector ; -> (AX DI)
add bx, [bpbBytesPerSector]
dec bp
jnz .Next
Поскольку иногда доступ к диску может быть невозможен по какой-то безвредной причине, мы повторяем операцию ограниченное количество раз. 5 хороший выбор. Ваша программа решила повторить в бесконечности, что я считаю сомнительным.
; IN (es:bx,cx,dx) OUT () MOD (ax,di)
ReadOneSector:
mov di, 5
.ReTry:
mov ax, 0x0201 ; BIOS.ReadSector
int 0x13 ; -> CF
jnc .OK
dec di
jz DiskFail
call ResetDisk
jmp .Retry
.OK:
ret
Загрузка первого FAT, конечно, аналогичный процесс.
И для загрузки файлового кластера вам повезло, поскольку у каждого кластера есть только один сектор на этом диске. Цикл не требуется.
Поиск через RootDir. Fifoernik уже говорил вам об опасности использования rep cmpsb
. Использование rep
вместо repe
заставило вас думать, что регистр DI
всегда будет продвигаться на 11, где на самом деле повторение может закончиться раньше.
Дополнительные проблемы здесь:
Вы не проверяете первый байт записи RootDir. Это жизненно важная информация, которую вы должны проверить. Если это 0, вы достигли конца RootDir, и бесполезно продолжать оценивать записи. Если это 0xE5, вход бесплатный, и вы должны просто пропустить его.
Вы не проверяете байт атрибута. Запись вполне может быть для каталога для идентификатора тома. Также не может быть файл, который вы ищете, поэтому пропустите запись!
Далее применяется вышеупомянутое:
mov di, DiskBuffer ; ES:DI but knowing that ES=DS
mov bx, [bpbRootEntries]
.CheckEntry:
cmp byte [di], 0
je .FileNotFound
cmp byte [di], 0xE5
je .SkipEntry
test byte [di+11], 00011000b ; DIR | VOL
jnz .SkipEntry ; Is not a file
mov si, r_name
mov cx, 11
push di
repe cmpsb
pop di
je .FileFound
.SkipEntry:
add di, 32
dec bx ; Counting downward is easier
jnz .CheckEntry
.FileNotFound
jmp Missing
.FileFound:
mov ax, [di+0x1A]
mov [cluster], ax
По цепочке кластеров. Ниже приведена формула для преобразования номера кластера N в номер сектора для его первого / единственного сектора:
FirstSectorOfCluster = FirstDataSecNum + (N - 2) * bpbSectorsPerCluster
= 51 + (N - 2) * 0x01
= N + 49
Эта часть вашей программы никогда не загрузит более 1 кластера файла из-за странного jge .jump
. Все номера кластеров good будут Greater . Инструкция cmp ax, 0xFFF8
при интерпретации со знаком (что делает jge
) гласит cmp ax, -8
. Таким образом, все номера кластеров от 2 до нескольких тысяч будут больше.
Совет: чтобы можно было загружать большой файл (размером более 64 КБ), вы должны изменить регистр сегмента ES
и сохранить смещение BX
на 0.
mov ax, 0x2000
xor bx, bx
LoadNextCluster:
add ax, bx
mov es, ax
xor bx, bx
mov ax, [cluster]
add ax, 49
call SetupCHS ; -> CX DX (AX)
call ReadOneSector ; -> (AX DI)
mov si, [cluster]
shl si, 1 ; You don't need MUL to calculate x2
mov ax, [DiskBuffer+si] ; FAT gives number of next cluster
mov [cluster], ax
cmp ax, 0xFFF8 ; End-of-file marker ?
mov ax, es
mov bx, 512 / 16
jb LoadNextCluster
Loaded: ; We have fully loaded the kernel
Части вашей программы, которые имеют дело с функциями отображения BIOS, имеют несколько собственных проблем, но я думаю, что это не то, что сейчас важно.
Если вам удастся отредактировать все эти изменения и до сих пор не получить результаты, вы можете опубликовать дополнительный вопрос с исправленной программой. (Если вы сделаете это сегодня, я могу еще раз взглянуть на это ...)
Никогда не включайте информацию, полученную из ответа, в свой первоначальный вопрос, если, конечно, вы не напишите это в отдельном разделе, но все же. Основные изменения требуют дополнительного вопроса (отдельный пост).