2016-09-16 4 views
0

Я написал загрузчик в сборке. Вот как это работает:Загрузочный загрузчик не загружает второй сектор

  1. Во-первых, BIOS загружает загрузчик, как обычно. Ему поручено отправиться в 200 часов.

  2. В 200h есть код, расположенный между 200h и 21Eh. Он просто переключается в режим VGA, рисует пурпурный пиксель на координатах 1,1, используя возможности VGA. Он навсегда завершает этот код.

Однако, когда я загрузить его, он просто идет на мигающий курсор, который обычный VGA .bin файл не будет делать, и будет отображать пиксель. Я проверил пиксель, и ничего не увидел. То, что я видел, означало, что код VGA не запускался, и загрузчик был просто загружен и ничего больше.

Код загрузчика:

cli 
startload: 
push 0x00000200 
ret 

times 510-($-$$) db 0 
db 0x55 
db 0xAA 

Вы можете видеть, что это просто перейти к следующему сектору (начиная с 200h) и код на 200h-21Eh:

BITS 16 
org 200h 
data: 
xcoord DB '1' 
ycoord DB '1' 
color DB 'D' 
.code: 
vga: 
mov ax, 13h 
int 10h 
mov ax, ycoord 
mov bx, xcoord 
mov cx, 320 
mul cx 
add ax, bx 
mov di, ax 
mov dl, color 
mov [es:di],dl 
jmp vga 

(Да я знаете, это не 230-байтовые байты, это размер скомпилированного выхода, который равен 230h.)

В чем проблема? Примечание. Это не обсуждает, как заставить его перейти во второй сектор. Он спрашивает, почему он туда не поедет. Я не нашел никаких решений.

+0

Можете ли вы показать код, загружающий второй сектор? –

+0

@MargaretBloom Это часть загрузки. Это всего лишь «push 0x00000200» и «ret». –

+3

Нет, это скачок к 'CS: 200h' (BTW скачок будет более ясным и более хорошо предсказанным). BIOS загружает только первый сектор, остальное зависит от вас. –

ответ

3

В ответ на один из ваших вопросов. Этот код:

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. Кстати, этот ответ был для вопроса, который у вас был в прошлом году.

+0

Если ваш bootload.bin правильно дополнен до 512B, вы также можете «cat bootload.bin stage2.bin/dev/zero | head -c 720K> диск.img'. Но метод dd по-прежнему ставит второй сектор со смещением = 512 независимо от размера первого двоичного файла. Также возможно: 'cat bootload.bin stage2.bin> disk.img && truncate disk.img -s $ ((720 * 1024))', чтобы сделать разреженный файл. –

+0

Я думаю, что истоки использования dd для таких вещей - это довольно древние мелочи. На некоторых Unix-системах вам приходилось использовать что-то вроде dd для записи для блокировки файлов устройств (например,/dev/fd0), потому что они принимали только записи, которые были выровнены по краям и написали полные блоки. Linux имеет буферный слой над блочными устройствами, поэтому вы можете делать что угодно. (Или вы можете открыть с помощью O_DIRECT, чтобы записи не проходили через буферный кеш). dd, безусловно, по-прежнему полезен для чтения/записи в смещениях в двоичных файлах, но в наши дни ничего особенного нет. (Не говоря, что вы сделали это заявление, просто забавный факт). –

+0

Это правда, однако использование метода DD исключительно работает на платформах Wndows и Linux, что удобно. В Windows вы получаете chrysocome DD и поддерживает псевдо-устройства, включая/dev/zero. Использование вашего метода потребует оболочки bash (cygwin, Msys, Msys2 и т. Д.), В которой есть другие связанные инструменты (head, cat, truncate). Также не случайно мой ответ на самом деле упомянул Chrysocome DD AND Widnows, поскольку он нацелен на не-Linux/* nix толпу, а также. Я узнал мой урок о принятии конкретных ответов Linux в прошлых отношениях с OS Dev people на SO. –

2

Похоже, что вам не хватает какого-то довольно важного кода, чтобы фактически прочитать второй сектор в памяти. Что-то вроде этого:

mov ah,0x02 ; read sectors into memory 
mov al,0x10 ; number of sectors to read (16) 
mov dl,[bootDrive] ; drive number 
mov ch,0 ; cylinder number 
mov dh,0 ; head number 
mov cl,2 ; starting sector number 
mov bx,Main ; address to load to 
int 0x13 ; call the interrupt routine 

Это предполагает, что вы сохранили значение dl в байты с меткой bootDrive. Очевидно, вам нужно будет изменить адрес, на который вы загружаете код.

Использование ORG 0x200 просто настраивает ассемблер для обработки генерации ссылок, не связанных с перемещением адресов.

+0

Собираюсь попробовать. –

+0

Назад; просто подпрыгнул до обычного загрузчика на жестком диске. Я увидел мигающий жесткий диск, который, кажется, с этим кодом перешел от загрузчика - загрузчик жесткого диска - инициализация/etc. графического меню загрузки, установленного на жестком диске. –

+0

@StarOS: Возможно, хорошая идея использовать симулятор, такой как BOCHS для разработки: тогда вы можете сделать один шаг кода вашего загрузочного сектора во встроенном отладчике и изучить регистры/память. Это намного проще, чем работать в основном слепым. –