Секторы чтения BIOS

Я задумался над созданием небольшой ОС ради обучения и сейчас использую загрузчик. Я хочу иметь возможность использовать int 0x13 для чтения секторов с дисковода гибких дисков, помещения их в память, а затем перехода к этому коду. Вот что у меня есть на данный момент:

org 0x7c00
bits 16

main:
    call setup_segments

    mov ah, 2      ; function
    mov al, 1      ; num of sectors
    mov ch, 1      ; cylinder
    mov cl, 2      ; sector
    mov dh, 0      ; head
    mov dl, 0      ; drive
    mov bx, 0x1000 ;
    mov es, bx     ; dest (segment)
    mov bx, 0      ; dest (offset)
    int 0x13       ; BIOS Drive Interrupt

    jmp 0x1000:0   ; jump to loaded code

times 510 - ($-$$) db 0 ; fluff up program to 510 B
dw 0xAA55               ; boot loader signature




LoadTarget: ; Print Message, Get Key Press, Reboot

jmp new_main

Greeting: db "Hello, welcome to the bestest bootloader there ever was!", 0
Prompt:   db "Press any key to reboot...", 0

Println:
    lodsb ; al <-- [ds:si], si++

    or al, al    ; needed for jump ?
    jz PrintNwl  ; if null is found print '\r\n'
    mov ah, 0x0e ; function
    mov bh, 0    ; page number ?
    mov bl, 7    ; text attribute ?
    int 0x10     ; BIOS Interrupt
    jmp Println

PrintNwl: ; print \r\n
    ; print \r
    mov ah, 0x0e ; function
    mov al, 13   ; char (carriage return)
    mov bh, 0    ; page number ?
    mov bl, 7    ; text attribute ?
    int 0x10

    ; print \n
    mov ah, 0x0e ; function
    mov al, 20   ; char (line feed)
    mov bh, 0    ; page number ?
    mov bl, 7    ; text attribute ?
    int 0x10

    ret          ; return

GetKeyPress:
    mov si, Prompt ; load prompt
    call Println   ; print prompt

    xor ah, ah     ; clear ah
    int 0x16       ; BIOS Keyboard Service

    ret            ; return

setup_segments:
    cli ;Clear interrupts
    ;Setup stack segments
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    sti ;Enable interrupts

    ret

new_main:
    call setup_segments

    mov si, Greeting ; load greeting
    call Println     ; print greeting

    call GetKeyPress ; wait for key press

    jmp 0xffff:0     ; jump to reboot address

times 1024 - ($-$$) db 0 ; fluff up sector

Я хочу загрузить сектор после LoadTarget в адрес 0x1000:0, а затем перейти к нему. Пока у меня просто пустой экран. Мне кажется, что ошибка находится где-то между main и строкой times 510 - ($-$$) db 0. Может я просто не понимаю значения регистра? Пожалуйста помоги! Спасибо


person Jerfov2    schedule 10.07.2015    source источник
comment
Поскольку setup_segments уже является вторым сектором, как вы ожидаете, что он будет работать, если он еще даже не загружен? Кроме того, установка ss без sp - очень плохая практика, у вас нет возможности узнать, где будет находиться ваш стек.   -  person Jester    schedule 10.07.2015
comment
@Jester, о да, не думал об этом;). Также где я должен установить sp?   -  person Jerfov2    schedule 10.07.2015
comment
stackoverflow.com/questions/2065370/ || stackoverflow.com/questions/19381434 /   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 04.10.2015


Ответы (2)


Вы должны заменить первый call setup_segments фактическими инструкциями, выполняющими работу. Также, как указал Шут, всегда обновляйте регистр SP при изменении регистра SS.

В настоящее время вы читаете данные из цилиндра 1. Это должен быть цилиндр 0.

Код для перевода строки - 10 (а не 20, как вы написали).

Оба вызова BIOS в PrintNwl не нуждаются в регистре BL, поскольку и CR, и LF не являются отображаемыми ascii.

person Fifoernik    schedule 10.07.2015
comment
Ничего себе, я не могу поверить, что испортил символ '\ n'! Я знал, что это 10, не знаю, почему поставил 20. Я исправлю и другие ошибки, спасибо! - person Jerfov2; 10.07.2015
comment
Спасибо за помощь, но экран по-прежнему отображается пустым. Я использую дискету в Virtualbox. Отличается ли она от настоящей дискеты с точки зрения использования? - person Jerfov2; 10.07.2015
comment
К сожалению, никогда не имел удовольствия работать с Virtualbox. - person Fifoernik; 10.07.2015
comment
Ничего страшного, моя программа вроде как работает, перезагружается, но ничего не отображает. Я думаю, это может иметь какое-то отношение к sp. Я не знаю, на что мне это установить. Мне просто скопировать ss в sp? - person Jerfov2; 10.07.2015
comment
@TheTromboneWilly правильно ли вы установили происхождение с помощью ORG? Разве это не должно быть 0 для второго этапа? - person ; 10.07.2015
comment
@ knm241 Если я снова попытаюсь установить org, я получу error: program origin redefined - person Jerfov2; 10.07.2015
comment
Nasm допускает только один org на файл. Один из способов справиться с этим - section kernel vstart=0 (любое произвольное имя - не обязательно ядро) - будет иметь эффект org 0. Другой способ - собрать файл отдельно и %incbin "kernel.bin" после вашего загрузочного сигнала. Другой способ - собрать два файла отдельно и объединить их с помощью cat или copy /b. Можно было бы записать их отдельно на дискету или поддельную дискету, но, вероятно, проще их объединить и записать один раз. osdev.org - ваш друг. - person Frank Kotler; 10.07.2015
comment
@FrankKotler Могу ли я также использовать сегментированный адрес для vstart, например section LoadTarget vstart=0x1000:0? - person Jerfov2; 10.07.2015
comment
@FrankKotler nvm я исправил - person Jerfov2; 11.07.2015
comment
Рад, что ты это починил. Нет, вы не можете использовать сегментированный адрес для vstart. Конечно, хочется сказать. В старые добрые времена у нас не было выбора, кроме как изучить модель сегментированной памяти ... и DOS. Вы, молодые ребята, должны изучить его для бутсекторов и перехода в pmode, но для чего-то еще он не годится. Это жизнь. - person Frank Kotler; 11.07.2015

Тот факт, что вы используете ORG 0x7C00, означает, что вы ожидаете, что пара или регистры CS: IP будут содержать 0000h: 7C00h. Помните, что BIOS уже поместил первые 512 байтов вашей программы длиной 1024 байта по линейному адресу 00007C00h.

Настройка других сегментных регистров - это просто копирование CS в DS, ES и SS. Но очень важно каждый раз, когда вы меняете SS, вы должны также менять SP, чтобы поддерживать согласованную пару регистров SS: SP. В вашей программе удобное место для стека будет под программой, поэтому я устанавливаю регистр SP на 7C00h. Вы не можете возиться с SS: SP в подпрограмме (как и вы), потому что RET в конце не знает, куда вернуться!

Когда вы загружаете 2-й сектор с дискеты, он должен поступать из цилиндра 0. В представлении CHS Цилиндр и Голова начинаются с 0, а Сектор начинается с 1.
Было бы неплохо, если бы вы проверили CF для успешной операции .

Перейти к загруженному коду нельзя через jmp 0x1000:0, потому что код, который находится там сейчас, является частью программы, которая была скомпилирована с помощью директивы ORG 0x7C00. Вам нужно это компенсировать!

  1. Компенсируйте директиву ORG 0x7C00. Вычтите 07C0h из части сегмента, добавьте 7C00h к части со смещением. => jmp 0840h:7C00h
  2. Компенсируйте тот факт, что ваша метка LoadTarget находится со смещением 512 внутри программы. Вычтите 0020h из сегментной части, добавьте 0200h к смещенной части. => jmp 0820h:7E00h

Вот как может выглядеть исходный код

 org 7C00h
 bits 16
main:
 mov ax,cs
 mov ds,ax  <-- Not necessary at this stage in this program
 mov es,ax  <-- (keep them should you display a message on error)
 cli
 mov ss,ax
 mov sp,7C00h
 sti
 mov ax,0201h
 mov cx,0002h
 mov dx,0000h
 mov bx,1000h
 mov es,bx
 mov bx,0000h
 int 13h
 jc  Error
 jmp 0820h:7E00h
Error:
 hlt

После запуска второго этапа вам нужно только настроить регистры DS и ES. CS: IP был настроен через JMP, а SS: SP просто продолжается.

 ...
new_main:
 push cs
 pop  ds
 push cs
 pop  es
 mov  si,Greeting
 call Println
 ...
person Sep Roland    schedule 12.07.2015