Вопросы загрузчика в сборке - PullRequest
0 голосов
/ 06 ноября 2011

У меня интересный вопрос, я пытался сделать простой загрузчик, который бы загружался и отображал текст. Проведя дальнейшие исследования, я обнаружил, что загрузчику необходимо резервировать память для чего-то. Вот мои вопросы:

  1. Как вы резервируете память для загрузчика?
  2. Зачем вам резервировать память?
  3. Какие еще функции требуется для предварительной загрузки загрузчика.
  4. Как передать управление ядру?

Ответы [ 3 ]

0 голосов
/ 16 октября 2016

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

Первое, что вы должны сделатьНужно познакомиться с 16-битной архитектурой ПК и особенно с его моделью сегментации.Он понадобится вам, чтобы понять, как написать первую часть загрузчика в 16-битном режиме.Далее вам нужно понять архитектуру i386 (32-битный режим), чтобы переключиться в защищенный режим и настроить регистры сегментов, пейджинг и т. Д.

Имейте в виду, что код BIOS является 16-битнымкод можно использовать только тогда, когда процессор находится в 16-битном режиме (реальный режим) через программные прерывания.После того, как вы переключитесь в защищенный режим, вы больше не сможете его использовать (если только вы не переключитесь обратно в 16-битный режим, который является громоздким).Хорошая ссылка на прерывания BIOS - это список прерываний Ральфа Брауна: http://www.ctyme.com/rbrown.htm

С точки зрения разработки ядра хорошим руководством для начала написания ОС для x86 с нуля является Учебное пособие по разработке ядра Джеймса Моллоя: http://raw.knusbaum.com/jamesmolloy/tutorial_html/

Он использует GRUB для загрузки своего ядра, что, вероятно, лучше всего сделать, так как GRUB уже переключает процессор в защищенный режим и настраивает GDT для вас.Тогда становится намного проще загрузить простое ядро ​​в C.

Если вы решите не использовать GRUB и писать все самостоятельно, вам придется использовать 16-битный код для загрузки вашего ядра с помощью программных прерываний изBIOS (см. Ссылку выше).Кроме того, если вы хотите, чтобы ваше ядро ​​было в формате ELF, вам придется написать загрузчик ELF.Имейте в виду, что загрузочный сектор, загружаемый BIOS, имеет длину ровно 512 байт.Это очень мало кода (на самом деле 510 байт, так как последние 2 для подписи загрузки).Вот почему загрузочные секторы загружают загрузчик 2-й ступени, который не имеет такого размера.

В любом случае, удачи в ваших начинаниях!

0 голосов
/ 07 июня 2019

Относительно ответа на ваш вопрос 1

1) Просто зайдите в файл линкера вашего проекта, и вы можете сделать что-то, как показано ниже.

2) Убедитесь, что вы также перемещаете свой вектор сбросас вашей векторной таблицей.

    MEMORY
    {
    /*  ------------------- BOOT LOADER CODE --------------------------------------*/
        BOOT_cached(RX) : ORIGIN = 0x08000000, LENGTH = 32K-0x40
        BOOT_uncached(RX) : ORIGIN = 0x0C000000, LENGTH = 32K-0x40

    /*  ------------------- USB INTERFACE -----------------------------------------*/
        USB_INTERFACE_cached(RX) : ORIGIN = 0x08007FC0, LENGTH = 0x40
        USB_INTERFACE_uncached(RX) : ORIGIN = 0x0C007FC0, LENGTH = 0x40

    /*  ------------------- APPLICATION CODE ------------------------------------- */
    /*  APP_cached(RX) : ORIGIN = 0x08008000, LENGTH = 256K-32K */
    /*  APP_uncached(RX) : ORIGIN = 0x0C008000, LENGTH = 256K-32K */

    /*  PSRAM_1(!RX) : ORIGIN = 0x1FFFC000, LENGTH = 0x4000 */
    /*  DSRAM_1_system(!RX) : ORIGIN = 0x20000000, LENGTH = 0x8000 */
    /*  DSRAM_2_comm(!RX) : ORIGIN = 0x20008000, LENGTH = 0x8000 */
    /*  SRAM_combined(!RX) : ORIGIN = 0x1FFFC000, LENGTH = 0x14000 */

        DSRAM_1_system(!RX) : ORIGIN = 0x2000D000, LENGTH = 0x3000
        SRAM_combined(!RX) : ORIGIN = 0x2000D000, LENGTH = 0x3000
    }

    stack_size = DEFINED(stack_size) ? stack_size : 4096;
    no_init_size = 64;

3) Кроме того, вы можете проверить правильность адреса таблицы векторов, проверив файл output.lst проекта, как показано ниже.

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .usb_interface 00000024  08007fc0  0c007fc0  0000ffc0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .text         000050f0  08000000  0c000000  00008000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 Stack         00001000  2000d000  2000d000  00015000  2**0
                  ALLOC
  3 .data         00000050  2000e000  0c0050f0  0000e000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .bss          000006a8  2000e050  0c005140  0000e050  2**2
                  ALLOC
  5 USB_RAM       00000e00  2000e6f8  2000e6f8  00015000  2**2
0 голосов
/ 06 ноября 2011

На самом деле вам не нужно «резервировать» память, просто используйте ее.

На самом деле, вам это нужно, потому что ваше ядро ​​ожидает начала адресуемой памяти.По этой причине первое, что вы должны сделать, это скопировать загрузчик, который, вероятно, будет запущен из MBR в этот момент, в верхнюю память (далеко за пределы ядра), а затем перейти к нему.Затем вам нужно загрузить ядро ​​в начало памяти, настроить остальную среду для ядра (опять же, он будет ожидать, что определенные вещи, такие как командная строка ядра Linux, будет в определенных местах в памяти), затем перейтидо его точки входа.

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

Это также может помочь вам разобраться на ранних этапах процесса загрузки: IBM

...