2015-03-12 5 views
2

Я пытаюсь загрузить немного данных с помощью моего загрузчика на USB, но, судя по всему, int 13h не будет работать!int 13h, похоже, не читает секторы, содержащие мое ядро ​​

Bootloader:

[bits 16] 
[ORG 0x7c00] 

jmp 0x0000:start 
start: 

cli 
xor ax, ax 
mov ss, ax 
mov sp, 0x7c00 

mov ax, cs 
mov ds, ax 
mov es, ax 
mov fs, ax 
mov gs, ax 
sti 

mov [driveno], dl 

reset: 
    ;reset drive 
xor ax, ax 
mov dl, [driveno] 
int 0x13 
or ah, ah 
jnz reset 


mov ah, 0x02 
mov al, 0x01 
mov bx, 0x0000 
mov es, bx 
mov bx, 0x7e00 

mov dl, [driveno] 

xor dh, dh 

mov cx, 0x0002 

int 0x13 
or ah, ah 
jnz reset 


mov dx, [0x7e00] ;So i can check and see if it has been loaded 
call printhex 

cli 
hlt 
jmp $ 

print: 
loop: 
lodsb 
or al, al 
jz done 
mov ah, 0x0e 
mov bx, 0x0003 ;page 0 and default color 
int 0x10 
jmp loop 
done: 
ret 

printhex: 
push bx 
push si 
mov si, hex_template 

mov bx, dx 
shr bx, 12 
mov bx, [bx+hexabet] 
mov [hex_template+2], bl 

mov bx, dx 
shr bx, 8 
and bx, 0x000f 
mov bx, [bx+hexabet] 
mov [hex_template+3], bl 

mov bx, dx 
shr bx, 4 
and bx, 0x000f 
mov bx, [bx+hexabet] 
mov [hex_template+4], bl 

mov bx, dx 
and bx, 0x000f 
mov bx, [bx+hexabet] 
mov [hex_template+5], bl 

call print 
pop si 
pop bx 
ret 

hex_template db '0x????',0 
hexabet db 'abcdef' 

driveno db 0  ;Storing dl 

times 510-($-$$) db 0 
dw 0aa55h 

dw 0x1234 ;This wont load!!!! 

times 510 db 0 

Я хочу, чтобы мой метод шестнадцатеричного распечатать 0x1234 на экран, но он печатает 0x0000 вместо этого! Я знаю, что мой метод hex dump работает, проблема в том, что 0x1234 никогда не загружается в первую очередь. Есть идеи?

Я работаю на Windows. Я компиляция и создание изображения с:

nasm -f bin -o boot.bin boot.asm 
dd if=boot.bin of=\\.\e: bs=512 count=2 

Я использую dd из chrysocome. Может ли кто-нибудь объяснить это поведение?

+0

Единственное, что выглядит «забавным» для меня, это 'of = \. \ E:'. Он должен работать, иначе вы не увидите никакой информации. То, что я привык использовать, - 'of =/dev/fd0' - у меня есть настоящий флоппи-дисковод. Я бы «ожидал», возможно, что-то вроде 'of =/dev/sdb' (?) Для USB. Это порт Windows 'dd'? Это объясняет мою путаницу. Я не вижу ошибок в вашем коде - на самом деле неплохо. Удачи! –

+0

Да, это оконный порт. Есть ли какая-нибудь другая программа, которую я могу попробовать? –

+0

«rawrite» может быть (я не знаком с инструментами Windows), но я думаю, что ваш 'dd' должен работать, иначе вы не увидите никакого вывода. Вернуться к 'int 13h'. Я думаю, что проверка 'ah' для номера ошибки будет работать, но указание ошибки - это флаг флага. Вы можете попробовать 'jc reset' ... –

ответ

2

Несмотря на то, что этот вопрос является старым, он выявляет проблему, о которой я знаю, был воспринят другими, которые заслуживают надлежащего ответа.

Frank Kotler указывает, что ваш код выглядит хорошо. Пара незначительные nitpicks у меня есть:

  • Перед использованием LODSB не указывать флаг направления с инструкцией CLD или STD. В вашем случае это должно быть CLD, так как вы ожидаете LODSB для продвижения в положительном направлении. Вы можете увидеть более подробное объяснение в другом StackOverflow answer Я написал.
  • Несмотря на то, что вы настроите 16-разрядный код, вы настраиваете fs и gs сегментные регистры, которые не доступны ни один 8086/8088/80286.

Проблема и решение

Вопрос заключается в использовании вами программы DD. Вы делаете:

dd if=boot.bin of=\.\e: bs=512 count=2 

Обычно вы будете использовать of=\\.\e: с двойной обратной косой черты, однако это не является причиной проблемы. \.\e: фактически не указывает на начало диска (или USB-накопитель). Он указывает на начало раздела, что E: указывает на. Из-за этого вы написали свой загрузчик в начале данных раздела, а не Master Boot Record (MBR). Новые версии DD поддерживают параметр, чтобы указать начало всего устройства (а не только раздел):

Изменения в версии 0.6beta1

новая функция ID =/од = для ввода и вывода диска диск. если это единственный раздел на диске, тогда выбирается весь диск. Например: если вы вставляете USB-диск и монтируется как f: тогда «id = f:» будет выбирать USB-диск (а не только раздел, например if = \.\ Е: бы)

Для записи в начале USB диск, что раздел E: является частью, вы можете сделать это (я предполагаю, что вы работаете в командной строке, как пользователь с правами администратора):

dd if=boot.bin od=e: bs=512 count=2 

Уведомление о том, как я указал (od=e:). od= (устройство вывода) означает, что мы хотим использовать весь раздел физических устройств E: принадлежит.

Объяснение наблюдаемого поведения

Что может быть интересен, почему ваш загрузчик, казалось, работали, но распечатывается 0x0000. Я предлагаю свое лучшее предположение, основанное на знании Windows.

Из-за проблемы с DD запись в начало раздела (а не начало диска) сектор №2 (на основе 1) фактически не содержит нашего маленького ядра. Сектор №1 даже не содержит загрузчика, который мы написали!

Теперь, если наш код был написан в разделе, почему наш загрузчик даже запустил и почему он напечатал неправильное значение (0x0000)?

Это произойдет, если вы отформатировали USB-накопитель в Windows. Что вы можете не понимать, так это то, что USB-накопитель по умолчанию отформатирован как жесткий диск с одним разделом, и один раздел помечен как загрузочный. Microsoft устанавливает загрузчик в MBR (первый сектор диска). Этот загрузчик Microsoft является Chainloader, и это, как правило, функционирует следующим образом (некоторые детали могут отличаться):

  • Установите сегмент стека и соответствующим образом
  • Сохранить DL [диск мы загружаться на]
  • Переместите себя с физического адреса 0x00007C00 в другом месте.
  • Перейти к смещению в новой ячейке памяти, где мы должны продолжать
  • Посмотрите на таблице разделов для раздела загрузочного
  • Read первого сектор (512 байт) на загрузочного разделе (не диск) в память при 0x00007C00
  • Восстановление DL со значением, сохраненным в первом шаге
  • FAR JMP на 0х0000: 0x7C00
  • Выполнения Партии загрузчик запускается так, как если бы BIOS загружался и сразу переходил на него.

Что мы имеем сейчас - загрузчик Microsoft MBR, считывающий первый сектор загрузочного раздела на USB-накопителе и выполняющий его. Первый сектор раздела - наш загрузчик, потому что мы использовали dd if=boot.bin of=\.\e: bs=512 count=2. Мы на самом деле писали два сектора. Второй сектор раздела (не диск) содержит наше ядро. Настолько эффективно, что наш загрузчик работает!

Итак, теперь мы знаем, почему наш загрузчик запущен, почему он напечатал неправильное значение?Теперь может быть яснее, что второй сектор диска не имеет нашего ядра, этот раздел содержит его. Диск для чтения (INT 13h) делает код:

mov ah, 0x02   ; Disk Read 
mov al, 0x01   ; Number of Sectors to read 
mov bx, 0x0000 
mov es, bx 
mov bx, 0x7e00   ; ES:BX location to read to 0x0000:0x7E00 
mov dl, [driveno] 
xor dh, dh 
mov cx, 0x0002   ; Read sector #2 (1-based, not 0-based) 
int 0x13 

Мы только что прочитал второй сектор диска, а не раздел. Скорее всего, второй сектор обнуляется и, следовательно, причина, по которой наш загрузчик считывает значение 0x0000.

Заключение

Если бы мы правильно написали в течение первых 2-х секторов (1024 байт) диска (с DD), то наш загрузчик и ядро ​​бы работал нормально ..

Благодаря Microsoft и его загрузчик цепочек - наш загрузчик работал, но ядро ​​находилось не на том месте на диске, и мы распечатали сектор, который, вероятно, заполнен нулями. Эта цепочка событий заставила запустить наш загрузчик и показала, что int 13h не удалось. Вероятно, это вообще не сработало, он просто прочитал сектор, который не содержал наше ядро.

Примечание: Я использую слово kernel, но в контексте этого вопроса он относится к данным (0x1234), хранящимся во втором секторе.

+0

Очень интересный ответ. Спасибо, что объяснили это. Я обязательно буду помнить об этом в будущем! –