#assembly #qemu #bootloader #sector
#сборка #qemu #загрузчик #сектор
Вопрос:
Я кодирую простую программу, которая загружает сектор (номер сектора.2) в ОЗУ
но ничего не печатает.
сначала я попробовал этот код для bootsector:
org 0x7c00
mov ax, 0x1000 ; ES:BX = 1000:0000
mov es, ax
mov bx, 0x00
LoadSectortoMemory:
mov al, 0x01 ; Load 1 sectors
mov ah, 0x02 ; Load disk data to ES:BX
mov cl, 0x02 ; Sector = 2
mov ch, 0x00 ; Cylinder = 0
mov dl, 0x00 ; Drive = 0
mov dh, 0x00 ; Head = 0
int 13h ; Read
jc LoadSectortoMemory ; ERROR => Try again
jmp 0x1000:0x0000
times 510-($-$$) db 0
dw 0xaa55
ядро, которое принимает имя пользователя и пароль от пользователя, затем завершает программу:
mov si,Username
call Write
call Read
call Next_Line
call Pass
call Read
call Next_Line
call Kernel_Exit
Write:
mov al,[si]
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
inc si
mov dl,[si]
cmp dl,0x00
jne Write
ret
Read:
mov ah,0x00
int 0x16
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
cmp al,0x0d
jne Read
ret
Pass:
mov si,Password
call Write
ret
Next_Line:
mov al,0x0a
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
ret
Kernel_Exit:
mov si,Done
call Write
mov ah,0x4c
int 0x21
Username db 'Username: ',0
Password db 'Password: ',0
Done db 'Done',0
times 510-($-$$) db 0
и не сработало
после поиска я попробовал этот код (просто регистры добавлены в конце:/):
bits 16
org 0x7c00
mov ax, 0x1000 ; ES:BX = 1000:0000
mov es, ax
mov bx, 0x00
LoadSectortoMemory:
mov al, 0x01 ; Load 1 sectors
mov ah, 0x02 ; Load disk data to ES:BX
mov cl, 0x02 ; Sector = 2
mov ch, 0x00 ; Cylinder = 0
mov dl, 0x00 ; Drive = 0
mov dh, 0x00 ; Head = 0
int 0x13 ; Read!
jc LoadSectortoMemory ; ERROR => Try again
mov ax, 0x1000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x1000:0x0
times 510-($-$$) db 0
dw 0xaa55
снова не сработало
командные строки, которые я использую:
nasm -fbin BootSector.asm -o Bootsector.bin
nasm -fbin Kernel.asm -o Kernel.bin
cat BootSector.bin Kernel.bin > Code.bin
qemu-system-x86_64 Code.bin
это проблема с qemu?
кто-нибудь может помочь мне с моей проблемой?
заранее спасибо
Комментарии:
1. Работает для меня, если вы укажете
qemu-system-i386 -fda code.bin
, не уверен, почему.2. О, конечно. Вы устанавливаете
mov dl, 0
, что приводит к обнулению диска. Удалите эту строку, чтобы использовать модуль ROM-BIOS, инициализированный загрузчиком, и он будет работать без-fda
.3. @ecm большое тебе спасибо, приятель. мне очень помогло. просто вопрос: без добавления ax в fs и gs и другие регистры (2-й загрузочный сектор, который я пробовал), он печатает что-то необычное. почему это происходит?
4. Обратитесь ко второму пункту моего ответа. Установка
fs
,gs
, иes
не требуется.ds
Требуется настройка.
Ответ №1:
В вашем коде есть несколько проблем. Во-первых, самый важный:
LoadSectortoMemory:
mov al, 0x01 ; Load 1 sectors
mov ah, 0x02 ; Load disk data to ES:BX
mov cl, 0x02 ; Sector = 2
mov ch, 0x00 ; Cylinder = 0
mov dl, 0x00 ; Drive = 0
mov dh, 0x00 ; Head = 0
int 0x13 ; Read!
jc LoadSectortoMemory ; ERROR => Try again
Это работает, только если вы загружаетесь с нулевого диска. По умолчанию qemu настраивает ваш образ как диск 80h (hda = первый жесткий диск). Предполагается, что вы загружены с устройства 0 (fda = первая дискета). Поэтому вам нужно либо использовать параметры -fda code.bin
, чтобы указать qemu использовать ваш файл в качестве образа дискеты, и / или удалить строку, изменяющую dl
, чтобы использовать модуль для загрузки, инициализированный ROM-BIOS, прежде чем он передаст управление вашему загрузчику.
Вы уже модифицировали свой загрузчик для установки сегментных регистров. Особенно ds
необходимо установить значение 1000h, потому что ваше ядро использует этот сегментный регистр (неявно) для доступа к своим сообщениям. (В вашем kernel.asm нет org
строки, поэтому NASM использует значение по умолчанию org 0
here .) Вместо настройки ds
в загрузчике вы также можете добавить следующее в начало kernel.asm:
push cs
pop ds
Для этого устанавливается ds
значение cs
. В режиме реального 86 это допустимо для получения ссылки на сегмент данных с тем же базовым адресом, что и сегмент кода (но с разрешениями на чтение / запись).
Помимо настройки ss
, вы также должны установить sp
. Вы должны установить sp
в следующей инструкции тот, который устанавливает ss
. Пример:
mov ax, 1000h
cli
mov ss, ax
xor sp, sp
sti
Это значение устанавливается sp
равным нулю. Из-за недостаточного потока первый используемый слот стека будет находиться в ss:0FFFEh
(вверху полного сегмента 64 КБ).
В Kernel_Exit
вы используете службу прерывания 21h 4Ch. Эта служба недоступна для вас в этой среде. Вы должны использовать что-то еще, например, это:
xor ax, ax
int 16h ; wait for key pressed
int 19h ; reboot
Или это:
sti
halt:
hlt ; wait for external interrupt, keep CPU usage low
jmp halt ; jump infinitely to stop program flow
У Next_Line
вас есть это:
Next_Line:
mov al,0x0a
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
ret
Это работает только потому, что каждый раз, когда вы используете Next_Line
, вы ранее использовали Read
, который заканчивается, когда он отображает завершающий 13 (CR = возврат каретки). Next_Line
, чтобы быть более общим, сначала должно отображаться 13 (CR), а затем 10 (LF = перевод строки). То есть вы должны сделать это:
Next_Line:
mov al, 13
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
mov al, 10
int 10h
ret
Вы используете строку times 510-($-$$) db 0
в конце kernel.asm. Вместо этого вы должны использовать times 512 - ($ - $$) db 0
, чтобы заполнить весь сектор, а не только до 510 байт.