Загрузка старого загрузчика в сборке x86

Я пишу свой собственный загрузчик в NASM x86 на архитектуре x86_64, для начала я просто пытаюсь скопировать существующий загрузчик во второй сектор с помощью dd, затем скопировать его обратно и запустить из сборки.

файл.asm

org 0x7c00

jmp 0:start

start:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x8000

mov           ah, 0x02
mov           al, 1
mov           dl, 0x80
mov           ch, 0
mov           dh, 0
mov           cl, 3
mov           bx, 0x7e00
int           0x13

jmp 0x7e00
times 510-($-$$) db 0
dw 0xaa55

times (1024 - ($ - $$)) db 0x00
third_sector:
mov           ah, 0x02
mov           al, 1
mov           dl, 0x80
mov           ch, 0
mov           dh, 0
mov           cl, 2
mov           bx, 0x7c00
int           0x13

jmp           0x7c00

Код настраивает стек, затем заменяет себя на 1024 байта нулями, чтобы последний бит кода находился в третьем секторе диска, затем загружает второй сектор с диска в первый и переходит к первому сектору.

src.sh

#!/bin/bash
dd bs=1 count=512 if=/dev/c0d0 of=tmp
nasm -f bin file.asm -o file 
dd bs=1 count=1200 if=file of=/dev/c0d0
dd bs=1 count=512 seek=512 if=tmp of=/dev/c0d0

Что я делаю, так это копирую исходный загрузчик во временный файл с именем tmp, затем компилирую свою программу и помещаю ее в место старого загрузчика (/dev/c0d0, так как я работаю над MINIX 3.3.0), затем перемещаю старый загрузчик во второй сектор.

Результатом является строка «Загрузка с жесткого диска», что нормально, а затем я получаю «Ошибка загрузки NetBSD MBR P», что соответствует «нету раздела netBSD».

Изменить: вставлен неправильный файл asm. Второе редактирование: ошибка изменилась, но все еще сохраняется.


person MWaw    schedule 02.04.2017    source источник
comment
этот источник полный? Какие инструкции после mov sp, 0x8000?? Кстати, вы можете включить старый загрузчик непосредственно в свой исходный код с помощью incbin... но если этот старый загрузчик уже находится во втором секторе, вы можете просто скомпилировать + сохранить только загрузчик первого сектора. И переместите этот код третьего_сектора в загрузчик первого сектора, затем переместите его в некоторую свободную память, чтобы он не был перезаписан при загрузке оригинала, загрузки оригинала и перехода к его началу.   -  person Ped7g    schedule 02.04.2017
comment
@ Ped7g Я никогда не слышал об incbin, можете ли вы рассказать об этом подробнее? Но, тем не менее, я, возможно, не смогу использовать это, поэтому я хотел бы сделать это «сложным» способом.   -  person MWaw    schedule 02.04.2017
comment
Можешь проверить, запускается ли старый загрузчик безопасным jmp 0:0x7c00 дальним прыжком?   -  person Ped7g    schedule 02.04.2017
comment
@Ped7g Та же ошибка сохраняется, netBSD не видит раздел, но, насколько я вижу, это после этапа MBR wiki.netbsd.org/how_netbsd_boots_on_x86.   -  person MWaw    schedule 02.04.2017
comment
Я не знаю, что вы сделали, я спросил о дизассемблировании (запуске) оригинального загрузчика... о вашем текущем коде. Меня не интересует os-dev, поэтому я никогда не следил за этим внимательно, но разве BIOS не загружает только первый загрузочный сектор, т.е. только 512В? Так у тебя третья часть не загружается? Я считаю, что вы должны втиснуть все в свой первый 512B и либо загрузить оттуда дополнительные сектора, либо переместить биты кода вверх с помощью memcpy, чтобы вы могли загрузить исходный загрузочный сектор из 7c00 и выполнить его.   -  person Ped7g    schedule 02.04.2017
comment
@ Ped7g Я не знаю, как получить исходный код загрузчика, извините за это. Про вторую часть - из того, что я читал и слышал, можно сначала читать сектора потом прыгать на них таким образом, я без проблем могу все впихнуть сначала в 512Б, но потом после прочтения старого загрузчика уже не могу прыгнуть на начало.   -  person MWaw    schedule 02.04.2017


Ответы (2)


Загрузочная запись тома NetBSD (называемая NetBSD загрузочной записью раздела или PBR) считывает первый блок диска, с которого он был загружен, и проверяет, совпадает ли он с самим собой. Если это не так, то он предполагает, что на диске есть MBR, и пытается найти загрузочный раздел NetBSD в MBR. Он выполняет эту проверку путем простого сравнения первых 4 байтов себя, загруженных в память, и первых четырех байтов первого сектора на диске.

Поскольку ваш новый загрузочный сектор не начинается с тех же самых 4 байтов, он интерпретируется как MBR с таблицей разделов. Поскольку в вашем загрузочном секторе на самом деле нет таблицы разделов MBR, NetBSD VBR не может найти раздел NetBSD и поэтому печатает error P (возможно или error no slice, в зависимости от того, как он был настроен).

Чтобы решить эту проблему, вам нужно скопировать таблицу разделов вашего диска в новую MBR. Обратите внимание, что это также необходимо, потому что сама NetBSD (или что-то еще, что вы загружаете) также захочет прочитать таблицу разделов.

Если на вашем диске нет MBR с таблицей разделов, а вместо этого он начинается с NetBSD VBR (PBR), то вы мало что можете сделать, чтобы решить эту проблему. В этом случае, когда NetBSD VBR загружается нормально, она загружает первые 15 секторов в память с адресом 0000:1000, проверяет, совпадают ли первые четыре байта с самим собой, как описано выше, и если да, то переходит к коду, загруженному с адресом 0000:1000. Поскольку вы изменяете первые 3 сектора диска, вы также перезаписываете метку диска NetBSD в секторе 2 и начало того, что NetBSD называет начальной загрузкой фазы 1 (bootxx) в секторе 3.

person Ross Ridge    schedule 02.04.2017
comment
Именно так, я сам исправил ранее, но забыл отредактировать пост. - person MWaw; 03.04.2017

Я без проблем могу все впихнуть сначала в 512Б, но потом после прочтения старого загрузчика уже не могу прыгнуть в начало

Конечно, вы не можете одновременно работать в области 7C00-7DFF, а также загружать в нее другой сектор, поэтому вам нужно подготовить некоторый код, который будет работать за пределами 7C00-7DFF, он загрузит исходный загрузочный сектор в область 7C00-7DFF. ожидаемый 0000:7C00, и выполните его так же, как это сделал бы BIOS.

Я попытался изменить ваш код, чтобы он работал так, но у меня нет средств для отладки/проверки, работает ли он, поэтому действуйте осторожно (я использовал ndisasm для дизассемблирования полученного бинарного файла, и все выглядит нормально, т.е. перемещенный код не зависит по его адресу, поэтому вы можете свободно перемещать его в любую память, и он должен загрузить + выполнить этот сектор на 7C00.

Только убедитесь, что вы ничего не добавляете в этот код, что может сломаться после переезда на 7e00.

org 0x7c00

jmp 0:start

start:
mov ax, cs     ; ax = 0
mov ds, ax
mov es, ax
mov ss, ax
mov sp, ax     ; ss:sp = 0:0
; relocate second boot loader code outside of 7C00-7DFF (to 7E00)
mov si, boot_loader_code   ; address of code to relocate
mov di, 0x7e00             ; new address of code
mov cx, boot_loader_code_length
cld
rep movsb
; execute the relocated second boot loader
jmp 0x7e00

boot_loader_code:
    ; load second boot loader to 0:7c00 and execute it
    mov     ah, 0x02    ; load sector service
    mov     al, 1       ; load 1 sector
    ; mov     dl, 0x80    ; drive 0
    ; DL is set by BIOS originally
    ; and this code did/will not change it
    mov     ch, 0       ; track/cylinder
    mov     dh, 0       ; head number
    mov     cl, 3       ; sector number
    mov     bx, 0x7c00  ; es:bx pointer to buffer
    int     0x13        ; BIOS "load sector" service
    jmp     0:0x7c00
boot_loader_code_length EQU ($ - boot_loader_code)

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

все еще не работает

Ну, вы вряд ли сможете программировать на ассемблере без отладчика, слишком много того, что может пойти не так, и каждая деталь может иметь значение. Если у вас есть опыт работы с ассемблером, вы можете вытащить его, но если вы учитесь, приобретите какой-нибудь эмулятор ПК, где вы также сможете отлаживать такие вещи, как bochs. И сначала используйте документацию (например, ваш комментарий incbin, он, конечно, описан в документации NASM, что именно он делает).

Я поправил исходники по комментариям Михаила, но у меня до сих пор нет возможности его проверить/отладить (лень ставить бокс + научиться настраивать сектор загрузчика), но сам код "ок", он делает в основном то, что комментирует сказать. Достаточно ли этого или правильно для загрузки ПК, это другой вопрос. Это просто устраняет очевидную проблему вашего кода, связанную с попыткой иметь «третью» часть за пределами вашего односекторного блока 512B.

person Ped7g    schedule 02.04.2017
comment
Ну, все еще не работает, прямо сейчас он просто зависает, но спасибо за вклад! - person MWaw; 02.04.2017
comment
Если вы собираетесь использовать movsb и связанные с ним строковые инструкции, я настоятельно рекомендую использовать CLD для очистки флага направления, чтобы гарантировать движение вперед. Кроме того, загрузочный диск, с которого загружается BIOS, находится в регистре DL. Обычно не одобряют жесткое кодирование значения диска, например 0x80. Используйте тот, который был передан исходному загрузчику, и убедитесь, что значение все еще находится в DL до окончательного jmp 0:0x7c00 - person Michael Petch; 02.04.2017
comment
Я бы подумал об изменении SP на 0 вместо 8000. Вы будете перемещать код в ту же 512-байтовую область, где стек растет вниз. Это может показаться незначительным, но некоторые вызовы int 0x13 (зависит от BIOS) могут выделять изрядное количество места в стеке для выполнения работы. Установив SP в 0, вы можете остаться в первых 64 КБ, но начать рост указателя стека вниз от вершины первой области 64 КБ, что снижает вероятность того, что стек будет мешать выполнению кода. Часто я устанавливаю SP на 0x7c00, чтобы он увеличивался в нижней части памяти. Я обычно удостоверяюсь, что там, где я помещаю его, есть хорошие 4 КБ. - person Michael Petch; 02.04.2017
comment
@MichaelPetch спасибо, я попытался исправить это, следуя вашим советам, выглядит хорошо для меня. Но я не планирую на самом деле пробовать это, так что кто знает... - person Ped7g; 02.04.2017
comment
На самом деле проблема не в этом. Код в вопросе загружает третий сектор диска в 0x7e00, переходит к нему, и именно этот код загружает второй сектор в 0x7c00, а затем переходит к нему. - person Ross Ridge; 03.04.2017