Ваш FAR CALL для 0xF000: 0x0000 не работает, потому что это не адрес Int 0x13 в вашей таблице прерываний.Хотя 0xF000 выглядит как разумный сегмент в области BIOS, вероятность того, что вектор Int 0x13 начинается со смещения 0x0000, не очень высока.
Я потратил немало времени на этот вопрос, но некоторая настойчивость окупилась.Я нашел конкретный BIOS Intel, который демонстрирует такого рода странное поведение.Если физический адрес для записи начинается с 0x00000, запись возвращает успех, но данные неверны.В моей системе, кажется, записывается часть памяти BIOS, а не IVT.Подобные ошибки в BIOS встречаются, но некоторые случаи их обнаружения трудно найти, если вы не намеренно отлаживаете BIOS.Вероятно, это осталось незамеченным, потому что запись памяти с 0x0000: 0x0000 с Int 0x13 - это не то, что вы видите каждый день.Информация о моем BIOS:
BIOS Manufacturer: Intel
Version: CR94510J.86a.0045.2007.0418.1532
Date:April 18th, 2007
Кроме того, вы можете использовать другой механизм, отличный от записи на диск.Вы можете получить записи IVT, отображая их на экране, выводя их на последовательный порт и т. Д. Вы можете написать код для прямого доступа к контроллеру жесткого диска вместо использования Int 0x13, чтобы сделать это за вас.
Я не пытался обновить BIOS, хотя История изменений BIOS ничего не говорит об этой ошибке / функции.
Чтобы найти обходные пути, я дажеЯ старался отключить линию A20 , чтобы я мог попробовать другой сегмент: адреса смещения, которые сопоставляются с тем же физическим адресом 0x00000.0xFF00: 0x1000 = 0x10000, 0xFFFF: 0x0010 = 0x10000 и 0x0000: 0x0000 = 0x00000.Когда A20 выключен, физический адрес 0x10000 равен 0x00000.Если я начну читать со второй записи в IVT с 0x0000: 0x0004, то это абсолютно не проблема.
Это очень пахнет как ошибка.Я не мог найти никакой работы, кроме как скопировать таблицу IVT в другое место в памяти (я скопировал ее сразу после загрузчика) и затем записать ее на диск.Я взял ваш оригинальный код и улучшил его:
- Скопируйте 1024-байтовый IVT в 0x0000: 0x7e00.
- Сохраняйте прерывания включенными с помощью STI (хотя вы, вероятно, все еще можете использовать CLI).
- Использовать номер загрузочного диска, переданный BIOS в регистре DL .Это позволяет нам записывать (или читать) диск, который был загружен, без необходимости жесткого кодирования значения.
- Повторите операцию с диском 3 раза до сбоя с сообщением об ошибке.
- Сообщите пользователюкогда операция с диском говорит, что она прошла успешно.
- Предлагает пользователю нажать любую клавишу перед продолжением цикла загрузки.
- Поскольку я использовал эмуляцию USB и жесткого диска, мне пришлось добавить таблицу разделов сзагрузочная запись.Раздел является самоссылочным и делает весь диск похожим на раздел с MBR в качестве первого сектора.Это может быть удалено, если вы загружаетесь с настоящих жестких дисков, но его сохранение не должно повредить.
- Прокомментировал код
boot.asm :
DISK_RETRIES EQU 3 ; Retry disk operation 3 times on error
bits 16
org 0x7c00
start:
xor ax, ax
mov es, ax ; Set ES=0
mov ds, ax ; Set DS=0
mov ss, ax
mov sp, 0x7c00 ; Place our stack below the bootloader @ 0x0000:0x7c00
sti ; Enable external interrupts
; Appears to be a bug with Int 0x13 on some BIOSes where an attempt
; to write to disk from the physical address 0x00000 fails. Copy the
; 1024 byte IVT from 0x0000:0x0000 to 0x0000:0x7e00 just after bootloader
mov di, 0x7e00 ; Destination ES:DI = 0x0000:0x7e00
mov si, 0x0000 ; Source DS;SI = 0x0000:0x0000
mov cx, 1024/ 2 ; IVT is 512 16-bit words
rep movsw ; Copy all 512 words (1024 bytes)
write_sector:
mov bp, DISK_RETRIES ; Set disk retry count
; Write CHS=(0,0,4)
mov es, ax
mov bx, 0x7e00 ; ES:BX=0x0000:0x7e00 where copy of the IVT resides
mov cx, 0x0004 ; ch=cylinder=0, cl=sector=4
xor dh, dh ; dh=heads=0
; Use DL passed by the BIOS
.retry:
mov ax, 0x0302 ; Call function 0x03 of int 13h (write sectors)
; AL = 2 = Sectors to write
int 0x13 ; Write 512 bytes from memory @ 0x0000:0x7e00
; to CHS=(0,0,4) LBA=3 on the boot drive
jc .disk_error ; If CF set then disk error
.success:
mov si, successMsg ; Display messageabout success
call print_string
mov si, anyKeyMsg ; Press any key
call print_string
xor ax,ax ; Wait for keystroke
int 0x16
xor ax,ax ; Tell BIOS to continue and disk non-bootable
int 0x18 ; Our bootloader has exited back to BIOS at this point
.disk_error:
xor ah, ah ; Int13h/AH=0 is drive reset
int 0x13
dec bp ; Decrease retry count
jge .retry ; If retry count not exceeded then try again
error_end:
; Unrecoverable error; print drive error; enter infinite loop
mov si, diskErrorMsg ; Display disk error message
call print_string
end_loop:
hlt
jmp end_loop ; Infinite loop to prevent processor from
; getting past this point.
; Function: print_string
; Display a string to the console on display page 0
;
; Inputs: SI = Offset of address to print
; Clobbers: AX, BX, SI
print_string:
mov ah, 0x0e ; BIOS tty Print
xor bx, bx ; Set display page to 0 (BL)
jmp .getch
.repeat:
int 0x10 ; print character
.getch:
lodsb ; Get character from string
test al,al ; Have we reached end of string?
jnz .repeat ; if not process next character
.end:
ret
diskErrorMsg: db "Unrecoverable disk error!", 0x0d, 0x0a, 0
successMsg: db "Successfully written data to disk!", 0x0d, 0x0a, 0
anyKeyMsg: db "Press any key to continue...", 0x0d, 0x0a, 0
times 446-($-$$) db 0 ; Pad remainder of boot sector up to first partition entry
part1_entry:
db 0x80 ; Bootable partiion
db 0x00, 0x01, 0x00 ; CHS of first absolute sector (MBR) of hard drive
; Head=0, Sector=1, Cylinder=0
db 0x0c ; Partition type (has to be non-zero)
; 0x0c = Win 95 FAT32 (LBA)
db 0x00, 0x01, 0x00 ; CHS of last absolute sector (MBR) of hard drive
; Head=0, Sector=1, Cylinder=0
; We are effectively saying Size of partition is 1 sector
dd 0x0 ; LBA of first absolute sector (0=MBR)
dd 0x1 ; Number of sectors in partition. We set it to 1 but if you
; wish you could set it to the number of sectors on the disk
times 510-($-$$) db 0 ; Pad remainder of boot sector up to boot signature. This zeroes
; partition entries 2,3,4 effectively making them inactive
dw 0xaa55
Он может быть встроен в загрузчик / MBR с помощью:
nasm -f bin boot.asm -o boot.bin
В моей реальной системе с этим загрузчиком, вместо получения памяти, которую я не запрашивал, этот код дал мнеПравильный сброс реального режима IVT.Шестнадцатеричный дамп представляется разумным, так как большинство записей имеют 0xF000 в качестве сегмента и ненулевое смещение:
0000000 ff53 f000 ff53 f000 e2c3 f000 27b8 f000
0000010 ff53 f000 ff54 f000 27b8 f000 27b9 f000
0000020 fea5 f000 e987 f000 27b9 f000 27b9 f000
0000030 27b9 f000 27ac f000 ef57 f000 27b9 f000
0000040 0014 c000 f84d f000 f841 f000 4902 f000 <--- offset 0x4c is Int 0x13 0xf000:0x4902
0000050 e739 f000 ec6a f000 e82e f000 efd2 f000
0000060 53b5 f000 e6f2 f000 fe6e f000 ff53 f000
0000070 ff53 f000 f0a4 f000 efc7 f000 7011 c000
0000080 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000090 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000a0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000b0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000c0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000d0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000e0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000f0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000100 ec59 f000 00b0 0040 f065 f000 6c11 c000
0000110 27b9 f000 27b9 f000 00c0 0040 27b9 f000
0000120 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000130 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000140 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000150 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000160 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000170 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000180 0000 0000 0000 0000 0000 0000 0000 0000
0000190 0000 0000 0000 0000 0000 0000 27b9 f000
00001a0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00001b0 27b9 f000 0014 c000 27b9 f000 27b9 f000
00001c0 660b f000 27a3 f000 27b9 f000 c394 f000
00001d0 2c77 f000 2794 f000 3229 f000 3229 f000
00001e0 0000 0000 0000 0000 0000 0000 0000 0000
... The remainder up to 0x400 was all zero