В ответ на один из ваших вопросов. Этот код:
startload:
push 0x00000200
ret
В значительной степени эквивалентно почти абсолютному прыжку в CS: 0x200. Мы не знаем, что значение в CS есть, но многие BIOS начнутся с CS = 0 и IP = 0x7c00 (но это не всегда так). Вы не можете полагаться на CS, являясь особым значением, если вы не установите его себе. В большинстве случаев CS, вероятно, равен нулю, что означает, что вы, вероятно, прыгаете на адрес физической памяти 0x00200 (0x0000: 0x0200). Это происходит в середине таблицы прерываний реального режима, которая работает от физического адреса 0x00000 до 0x003FF. Вероятно, переход к этому месту приведет к некоторому неопределенному поведению.
Вы можете загрузить ваш загрузчик в BOCHS, который имеет разумный отладчик, который понимает 16-битный реальный режим. Вы могли бы пройти через код и точно определить, что такое CS и где он перескакивает.
То, что вы, вероятно, пытаетесь выполнить, может быть выполнено с помощью следующего кода. Это простое изменение моего предыдущего Stackoverflow answer на другой вопрос. Чтобы понять, что делает этот код, см. Мой предыдущий ответ.
В двух словах BIOS считывает один сектор диска (512 байт) с диска, начиная с адреса физической памяти 0x7C00. Если вы хотите, чтобы другие сектора были загружены, вы должны написать код, который загружает их в память, а затем перейти к этому коду после загрузки.
В этом примере первый этап - это загрузчик, который загружает второй этап второго сектора из сектора 2 диска (сектор сразу после загрузочного сектора). В этом примере я собираюсь загрузить второй сектор сразу после первого по физическому адресу 0x07e00 через segment:offset пара 0x7e0: 0x0000. (0x07e0 < < 4) + 0x0000 = 0x07e00.
bootload.asm
bits 16
ORG 0x7c00 ; Bootloader starts at physical address 0x07c00
; At start bootloader sets DL to boot drive
; Since we specified an ORG(offset) of 0x7c00 we should make sure that
; Data Segment (DS) is set accordingly. The DS:Offset that would work
; in this case is DS=0 . That would map to segment:offset 0x0000:0x7c00
; which is physical memory address (0x0000<<4)+0x7c00 . We can't rely on
; DS being set to what we expect upon jumping to our code so we set it
; explicitly
xor ax, ax
mov ds, ax ; DS=0
cli ; Turn off interrupts for SS:SP update
; to avoid a problem with buggy 8088 CPUs
mov ss, ax ; SS = 0x0000
mov sp, 0x7c00 ; SP = 0x7c00
; We'll set the stack starting just below
; where the bootloader is at 0x0:0x7c00. The
; stack can be placed anywhere in usable and
; unused RAM.
sti ; Turn interrupts back on
reset: ; Resets floppy drive
xor ax,ax ; AH = 0 = Reset floppy disk
int 0x13
jc reset ; If carry flag was set, try again
mov ax,0x07e0 ; When we read the sector, we are going to read to
; address 0x07e0:0x0000 (phys address 0x07e00)
; right after the bootloader in memory
mov es,ax ; Set ES with 0x07e0
xor bx,bx ; Offset to read sector to
floppy:
mov ah,0x2 ; 2 = Read floppy
mov al,0x1 ; Reading one sector
mov ch,0x0 ; Track(Cylinder) 1
mov cl,0x2 ; Sector 2
mov dh,0x0 ; Head 1
int 0x13
jc floppy ; If carry flag was set, try again
jmp 0x07e0:0x0000 ; Jump to 0x7e0:0x0000 setting CS to 0x07e0
; IP to 0 which is code in second stage
; (0x07e0<<4)+0x0000 = 0x07e00 physical address
times 510 - ($ - $$) db 0 ; Fill the rest of sector with 0
dw 0xAA55 ; This is the boot signature
Второй этап будет загружен INT 13h/AH=2h сразу после загрузчика в памяти, начиная с физическим адресом 0x07e00.
stage2.asm
BITS 16
; ORG needs to be set to the offset of the far jump used to
; reach us. Jump was 0x7e0:0x0000 so ORG = Offset = 0x0000.
ORG 0x0000
main:
; Set DS = CS
mov ax, cs
mov ds, ax
; Set to graphics mode 0x13 (320x200x256)
mov ax, 13h
int 10h
; Set ES to the VGA video segment at 0xA000
mov ax, 0xa000
mov es, ax
vga:
; Draw pixel in middle of screen
mov ax, [ycoord]
mov bx, [xcoord]
mov cx, 320
mul cx
add ax, bx
mov di, ax
mov dl, [color]
mov [es:di],dl
; Put processor in an endless loop
cli
.endloop:
hlt
jmp .endloop
; Put Data after the code
xcoord DW 160
ycoord DW 100
color DB 0x0D ; One of the magenta shades in VGA palette
Код выше, является слегка измененной версией кода VGA, как у вас были ошибки. Ваш код VGA неправильно настроил сегмент ES на 0xA000, который является началом графической памяти VGA; он не надлежащим образом не ссылался на переменные (вы использовали их адреса, а не значения); размер координат был BYTE вместо WORD; определенные значения в переменных с символьными значениями ASCII. Я также переместил данные после кода.
Я изменил код, чтобы нарисовать пиксель в середине экрана 320x200, а затем контур бесконечно завершает программу.
В Linux (или Windows, с Chrysocome DD) с помощью NASM собрать, вы можете создать 720k загрузочный диск с этими командами:
dd if=/dev/zero of=disk.img bs=1024 count=720
nasm -f bin bootload.asm -o bootload.bin
dd if=bootload.bin of=disk.img conv=notrunc
nasm -f bin stage2.asm -o stage2.bin
dd if=stage2.bin of=disk.img bs=512 seek=1 conv=notrunc
Это строит bootload.bin
и помещает его в первый сектор образа диска, а затем создает stage2.bin
и помещает его в сектор 2 образа диска. Образ диска называется disk.img
.
Вы должны быть в состоянии проверить его с QEMU что-то вроде:
qemu-system-i386 -fda disk.img
Больше информации о DD использования можно найти в одном из других моих Stackoverflow answers. Кстати, этот ответ был для вопроса, который у вас был в прошлом году.
Можете ли вы показать код, загружающий второй сектор? –
@MargaretBloom Это часть загрузки. Это всего лишь «push 0x00000200» и «ret». –
Нет, это скачок к 'CS: 200h' (BTW скачок будет более ясным и более хорошо предсказанным). BIOS загружает только первый сектор, остальное зависит от вас. –