Описание:
В своих попытках создать простую автономную программу я написал простой загрузчик в первом секторе. Его цель - загрузить программу в память. Для этого я использую INT 13h с AH = 2. Код такой:
disk_load:
push dx ; Store DX on stack so later we can recall how many sectors were requested to be read,
; even if it is altered in the meantime.
mov ah, 0x02 ; BIOS read sector.
mov al, dh ; Read DH sectors.
mov ch, 0x00 ; Select cylinder 0.
mov dh, 0x00 ; Select head 0.
mov cl, 0x02 ; Start reading from second sector (i.e. after the boot sector).
int 0x13 ; BIOS interrupt.
; <!----here
pop dx
ret
load_software:
mov bx, 0x7e0
mov es, bx
xor bx, bx
mov dh, 66
mov dl, [BOOT_DRIVE]
call disk_load
Я все тренировал в VirtualBox 5.2.8, и он работал на отлично. Перемещение всего на вторую машину, на которой установлен VirtualBox 6.0.14, проваливается. Прерывание заканчивается с установленным CF, указывая на сбой.
Чтение отличного ответа в Загрузчик не переходит на код ядра Я исправил потенциальную проблему с неопределенным значением DS, которая могла вызвать проблемы. Если я остановлю и выгрузлю состояние ЦП непосредственно перед вызовом int 0x13
, я получу согласованное состояние на обоих виртуальных ящиках:
00: 00: 05.930849 eax = 00000280 ebx = 00007e00 ecx = 00000002 edx = 00000000esi = 00000000 edi = 0000fff0
00: 00: 05.930857 eip = 00007cc8 esp = 00007bf9 ebp = 00007bff iopl = 0 nv вверх ei pl nz na po nc
00: 00: 05.930864 cs ={0000 base = 0000000000000000 limit = 0000ffff flags = 0000009b} dr0 = 00000000 dr1 = 00000000
00: 00: 05.930877 ds = {0000 base = 0000000000000000 limit = 0000ffff flags = 00000093} dr2 = 00000000 dr3 = 00000000
00: 00: 05.930884 es = {0000 base = 0000000000000000 limit = 0000ffff flags = 00000093} dr4 = 00000000 dr5 = 00000000
00: 00: 05.930891 fs = {0000 base = 0000000000000000 limit =0000ffff flags = 00000093} dr6 = ffff0ff0 dr7 = 00000400
00: 00: 05.930898 gs = {0000 base = 0000000000000000 limit = 0000ffff flags = 00000093} cr0 = 00000010 cr2 = 00000000
00:00: 05.930904 сс = {0000 base = 0000000000000000 предел = 0000ffff flags = 00000093} cr3 = 00000000 cr4 = 00000000
00: 00: 05.930910 gdtr = 00000000000fe89f: 0047 idtr = 0000000000000000: ffff eflags = 00200246
При анализе всех значений я могу только заключить, что все входные параметрычтобы прерывания были настроены правильно. Состояние после дампа имеет CF и код ошибки:
00: 00: 08.984877 eax = 00000900 ebx = 00000000 ecx = 00000002 edx = 00000000 esi = 00000000 edi = 0000fff0
00: 00: 08.984887 eip = 00007cca esp = 00007bf9 ebp = 00007bff iopl = 0 nv up ei pl nz na po cy
00: 00: 08.984896 cs = {0000 base = 0000000000000000 предел = 0000ffff flags = 0000009bb} dr0 = 00000000 dr1 = 00000000
00: 00: 08.984909 ds = {0000 base = 0000000000000000 limit = 0000ffff flags = 00000093} dr2 = 00000000 dr3 = 00000000
00: 00: 08.984917 ru= {07e0 base = 0000000000007e00 limit = 0000ffff flags = 00000093} dr4 = 00000000 dr5 = 00000000
00: 00: 08.984925 fs = {0000 base = 0000000000000000 limit = 0000ffff flags = 00000093} dr6 = ffff0ff0 dr7 = 00000400
00: 00: 08.984934 gs = {0000 base = 0000000000000000 limit = 0000ffff flags = 00000093} cr0 = 00000010 cr2 = 00000000
00: 00: 08.984941 ss = {0000 base = 0000000000000000 ограничение= 0000ffff flags = 00000093} cr3 = 00000000 cr4 = 00000000
00: 00: 08.984948 gdtr = 00000000000fe89f: 0047 idtr = 0000000000000000: ffff eflags = 00200247
Принимая во внимание код ошибки AH=9
ошибка границы данных (попытка DMA через границу 64K или> 80h секторов) приводит меня кhttps://en.wikipedia.org/wiki/INT_13H, где сделано это утверждение:
Адресация буфера должна гарантировать, что полный буфер находится внутри данного сегмента, то есть (BX + size_of_buffer) <= 10000h. </p>
Это объяснит мои первоначальные проблемы, поэтому я сделал еще одно исправление, чтобы установить es=0x7e0
и bx=0
. Это состояние кода, который отображается выше. Однако даже этот код не работает с состоянием, описанным выше.
Дальнейшее тестирование показывает, что я могу успешно прочитать до 65 секторов, но 66 или более не удается. Будучи странным числом, я вычислил конец 65-го сектора: 0xffff. Так что проблема становится немного более запутанной.
Вопросы:
Должны ли мои решения es=0x7e0
и bx=0
избегать пересечения сегментов (как я понимаю, это должно быть)?
Если это так, то почему возникает проблема с пересечением линейного адреса?
Или можно пересечь сегмент, но не маркер 0xffff в линейном адресе?
Спасибо за помощь.