2016-09-01 6 views
1

Я следую инструкциям Ник Бланделл для программирования загрузочного сектора (https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf и https://www.youtube.com/watch?v=YvZhgRO7hL4). Мой код очень хорошо работает в моем эмуляторе qemu, однако, когда я запускаю его на физической машине, он будет сбой, когда я начну ссылаться на сегментные регистры. Мои учителя в школе не знакомы с программированием на низком уровне и не могут мне помочь. Вот мой загрузчик, здесь я аннотировал строки, которые приводят его к сбою со строкой CRASH (обратите внимание: когда я говорю об аварии, на самом деле он просто загружает мою ОС со следующего диска. Я загружаю этот код из внешнего HDD):Почему мой загрузчик сбой после добавления этой строки?

[bits 16] 
[org 0x7c00]   

mov bp, 0xffff 
mov sp, bp 
mov ax, 0x0000 
mov ds, ax 
;; mov es, ax ;; CRASH 
;; mov ss, ax ;; CRASH 

mov si, BOOT_MSG 
call print_string 
call print_newline 

mov si, INIT_SEG_MSG 
call print_string 
call print_newline 

;; mov dx, ds ;; CRASH 
;; call print_hex 
;; call print_newline 

;;mov dx, cs ;; CRASH 
;;call print_hex 
;;call print_newline 

;;mov dx, es ;; CRASH 
;;call print_hex 
;;call print_newline 

;;mov dx, ss ;; CRASH 
;;call print_hex 
;;call print_newline 

;; mov dl, 0x80   ;; disk where kernel is 
;; mov cl, 3   ;; start sect 
;; mov al, 1   ;; num sect 
;; mov bx, 0x7ef0  ;; RAM addr 
;; call load_kernel 

;; mov si, KERN_MSG 
;; call print_string 
;; call print_newline 

;; call switch_to_pm 

jmp $ 

%include "print.asm" 
%include "print_hex.asm" 
%include "disk.asm" 
%include "pm.asm" 

[bits 32] 
pm : 
    mov esi, PM_MSG 
    call print_string_pm 
    jmp 0x7ef0 
    jmp $ 
[bits 16] 

BOOT_MSG : db 'booted 16-bit to 0x7c00',0 
KERN_MSG : db 'loaded kernel to es 0x7ef0',0 
PM_MSG : db 'switched to 32-bit mode',0 
INIT_SEG_MSG : db 'init segment registers',0 

times 510-($-$$) db 0 
dw 0xaa55     ` 

Уверен, что у меня есть фундаментальное недоразумение, любая помощь будет оценена по достоинству. Вот мои печатные процедуры:

print_string : 
    push ax 
    _loop : 
     lodsb 
     cmp al, 0 
     je _end 

     mov ah, 0x0e 
     int 0x10 
     jmp _loop 
    _end : 
     pop ax 
     ret 

print_hex : 
    mov si, HEX_TEMPLATE 

    mov bx, dx 
    shr bx, 12 
    mov bx, [bx+HEXABET] 
    mov [HEX_TEMPLATE+2], bl 

    mov bx, dx  ;; bx -> 0x1234 
    shr bx, 8  ;; bx -> 0x0012 
    and bx, 0x000f ;; bx -> 0x0002 
    mov bx, [bx+HEXABET] 
    mov [HEX_TEMPLATE+3], bl 

    mov bx, dx  
    shr bx, 4 
    and bx, 0x00f 
    mov bx, [bx+HEXABET] 
    mov [HEX_TEMPLATE+4], bl 

    mov bx, dx  
    and bx, 0x0f  
    mov bx, [bx+HEXABET] 
    mov [HEX_TEMPLATE+5], bl 

    call print_string 
    ret 

    HEX_TEMPLATE : db '0x???? ',0 
    HEXABET : db 'abcdef' 

print_newline : 
    pusha 
    mov ah, 0x0e 
    mov al, 0x0d 
    int 0x10 
    mov al, 0x0a 
    int 0x10 
    popa 
    ret 
+1

'mov bp, 0xffff'' mov sp, bp' потенциально опасно. На стек указывается SS: SP. Вы не знаете, к чему настроен _SS_. Вы должны установить как SS, так и SP. PS: Указатель стека не должен быть нечетным номером (по соображениям производительности). Чтобы установить стек чуть ниже загрузчика, вы можете использовать 'xor ax, ax'' mov ss, ax'' mov sp, 0x7c00'. 'xor ax, ax' будет нулевым _AX_ (вы могли бы использовать более длинную инструкцию' mov ax, 0x0000' –

+0

Фактические инструкции типа 'mov dx, ds' не будут разбиваться сами по себе. Это должно быть что-то другое (что-то сделано после что mov). –

+0

Какой процессор находится на вашем реальном оборудовании? 8086? 80286? 80386? –

ответ

1

Так после много твердых сбрасывает, я нашел решение. Проблема заключалась в том, что то, о чем я думал, было проблемой, НЕ ПРОБЛЕМА. Поэтому я решил взять флешку и загрузить с компьютера моего отца. Он отлично работал. Поэтому я продолжал писать свой загрузчик на своем собственном компьютере. Я написал код для входа в режим PM, запустил его, отлично, без проблем. Затем я сделал еще одно изменение. Скопировал байты на флеш-диск, используя dd, и запустил его на компьютере моего отца. Но ждать. Изменение не появилось ... Так что я запустил dd еще несколько раз, обнулял диск и все равно ничего. Поэтому я ЗАПИСАЛ МОЙ КОМПЬЮТЕР, RAN DD AGAIN, И ЭТО РАБОТАЕТ. Проблема заключалась в том, что моя ОС (Ubuntu 16, не уверенный, если она уместна) выдала команду dd. Похоже, что/dev/sdb - это своего рода буфер, который на самом деле не записывается на диск, по крайней мере, после того, как я впервые удалил флешку. Возможно, это ошибка в ОС. Возможно, это ошибка в dd. Может быть, я что-то упустил. Кто знает. Проблема (как указано в комментариях) заключается в том, что я не знал, как работают блокировочные устройства Linux. См.: sync. По-видимому, изменения, которые я сделал, были CACHED и не написаны. В любом случае я буду использовать эмулятор с этого момента. Всем спасибо!

+0

Вы запустили 'sudo sync' (http://man7.org/linux/man-pages/man1/sync.1.html) или' eject/dev/sdb', прежде чем вытащить USB-накопитель? Блокировочные устройства Linux по умолчанию не синхронны. Кроме того, вы уверены, что диск, который вы хотели, был под sdb, когда вы его снова вставили? Посмотрите в '/ dev/disk/by-id' (и/или в других каталогах) –

+0

Я не запускал синхронизацию, я просто дергал эту штуку .... – disassembler

+0

В любом случае, да, только тест на реальном когда он работает на эмулированном оборудовании. Или совсем нет, если вы просто делаете это для удовольствия. Теоретически было бы хорошо знать, что вы думаете о состоянии вещей, когда BIOS переходит к вашему коду, чтобы убедиться, что у вас есть твердая ручка того, что делают все сегменты и регистры. –

1

BIOS нам иметь особенность о них в том, что состояние CS неизвестно. В Bochs и, вероятно, Qemu CS = 0, поэтому код с источником 0x7C00 будет работать. Реальное оборудование может передавать CS = 0x7C0, поэтому без соответствующего дальнего перехода в начале кодов вызовы почти абсолютных функций будут искажены 0x7C00 байт, а начало координат установлено на 0x7C00.

Решения:

org 0x7C00 

    jmp 0:Begin     ; Far jump so CS = 0 
Begin: 
    mov ax, cs 
    mov ds, ax 
    mov es, ax 

или

org 0 
    jmp 0x7C0:0     ; Far jump so CS = 0x7C0 

Это, вероятно, то, что происходит, и крах приходит print_string @ вызов, который на самом деле ищет кода @ 0xf8 ??.

+1

Он устанавливает _DS_ в ноль с 'mov ax, 0x0000 mov ds, ax'. _CS_ должен быть установлен только для почти абсолютных прыжков или если он использует таблицы перехода. Ни то, что он делает. Установка _ES_ необходима только в том случае, если вам это нужно. Показанный код не нужен в момент сбоя (хотя это необходимо для прерывания чтения диска). Поскольку он прокомментировал все звонки, трудно сказать, что он использовал, когда он не работал. Включил ли он код чтения диска? Я не знаю. SS: SP - еще одна проблема. Если есть две вещи, которые выделяются, это SS: SP и ES как возможные виновники. –

+0

вблизи абсолютных прыжков также относится и к таким вызовам. В этом коде не используется этот тип. –

+0

Кроме того, еще одна недостающая вещь - это уверенность в правильности установки флага направления. Он должен явно использовать _CLD_, чтобы сделать направление вперед, поскольку использование OP в _LODSB_ предполагает, что это так. –

Смежные вопросы