1 Востаннє редагувалося drWoZD (06.10.2013 17:23:45)

Тема: Multiboot ядро

Хочу поділитись з колективом Replace своїм останнім бидлокодом, який вітається зі світом без ОС.
boot.s

Прихований текст

.code32
.text
    .global loader                 

    .set FLAGS,    0x0             # Флаги для ядра
    .set MAGIC,    0x1BADB002        # 'Магічне' число для multiboot (в multiboot інше)
    .set CHECKSUM, -(MAGIC + FLAGS)  # Контрольна сума

    .align 4    # Обовязково треба вирівняти до int
    .long MAGIC 
    .long FLAGS
    .long CHECKSUM

    # Власне код який почне виконувати завантажувач
    
loader:
    movl  $(stack + 0x4000), %esp # Ініціалізація стеку
    movl  %eax, magic                # Збереження магічного числа. Можна опустити 
    movl  %ebx, mbd                  # Збереження структури з параметрами які передав завантажувач

    # Тут я вирішив ініціалізувати сторінкову адресацію
    
    movl  $page_table, %edi  
    movl  $0x87, %eax       # Перший запис в каталозі таблиць вказує на 4Мб сторінку
    stosl
    
    lea   0x1003(%edi), %eax  # Всі таблиці йдуть зразу після каталогу
    movl  $1023, %ecx         # # Заповнюю весь каталог
    
table_dir_loop:
    stosl 
    addl $0x1000, %eax
    loop table_dir_loop
    
    # Зараз буде заповнення таблиць
    
    movl  $0x00400007, %eax  # Перша сторінка в першій таблиці починається з 4Мб 
    movl  $1048576, %ecx     # Заповнюємо всі 1024 таблиці в кожній 1024 сторінки, тобто описуємо 4Гб

table_loop:
    stosl
    addl  $0x00001000, %eax
    loop  table_loop
    
    # Дозволяємо використання великих сторінок (В даному випадку 4Мб)
    movl  %cr4, %eax
    orl   $0x10, %eax
    movl  %eax, %cr4
    
    # Записуємо адресу каталогу таблиць в cr3
    movl  $page_table, %eax
    movl  %eax, %cr3
    
    # Вмикаємо сторінкову адресацію
    movl  %cr0, %eax
    orl   $0x80000000, %eax
    movl  %eax, %cr0
    
    # Викликаємо Сішну функцію
    call  cmain
    
    #  Забороняємо переривання
    cli  
    
hang:
    hlt          # Зупиняємо процесор
    jmp   hang   # На всякий випадок якщо процесор відновить роботу                 

.bss
    .lcomm stack, 0x4000             # Резервуємо місце під стек
    .comm  mbd, 4                    # Вказівник на структуру
    .comm  magic, 4                  # Місце під магічне число
    .align 0x1000                    # Каталог сторінок і таблиці треба вирівняти до 4кб
    .lcomm page_table, 0x00401000    # Власне резервування місця під Таблиці сторінок і каталог таблиць
 

main.c

Прихований текст

#include "multiboot.h"

/*Тут я думаю можна не коментувати*/

char current_row = 0, current_col = 0;

void cls()
{
    int i;
    for (i = 0; i < LINES * COLUMS; i++)
     putchar(' ');
    current_col = 0;
    current_row = 0;
}

static inline void outb( unsigned short port, unsigned char val )
{
    asm volatile( "outb %0, %1"
                  : : "a"(val), "Nd"(port) );
}

void set_cur_pos(unsigned char col, unsigned char row)
{
    unsigned short pos = (row * 80) + col;
    outb(0x3D4, 0x0F);
    outb(0x3D5, (unsigned char)(pos&0xFF));
    outb(0x3D4, 0x0E);
    outb(0x3D5, (unsigned char )((pos>>8)&0xFF));
}

int putchar(char ch)
{
    unsigned short* video_buff =(unsigned short*) VIDEO_BUFF;
    if (ch == '\n')
    {
    current_row++;
    current_col = 0;
    return 0;
    }
    if (current_col >= COLUMS)
    {
    current_col = 0;
    current_row++;
    }
    video_buff[(current_row * COLUMS) + current_col++] = (unsigned short)((BLACK << 12) | (WHITE << 8) | (ch));
    return 0;
}

void shr(int n, char* str, int len)
{
    while(n > 0)
    {
    str[n] = str[n-1];
    n--;
    }
    
}

void inttostr(int num, char* str)
{
    int temp;
    int i=0;
    do{
    shr(1, str, i);
    temp = num % 10;
    num /= 10;
    *str = (3 << 4) | (temp);
    i++;
    }while(num != 0);
    str[i] = 0;
}

int puts(char* str)
{
    while (*str != 0)
    {
    putchar(*str);
    str++;
    }
    putchar('\n');
    set_cur_pos(current_col, current_row);
    return 0;
}

int cmain()
{
    cls();
    puts("Hello, World!!!");
    return 0;
}

multiboot.h

Прихований текст

#define COLUMS    80
#define LINES     25
/*Адреса відеопам'яті*/
#define VIDEO_BUFF 0xb8000

/*Опис Кольорів*/
#define BLACK    0x0
#define BLUE    0x1
#define GREEN    0x2
#define LIGHTBLUE 0x3
#define RED    0x4
#define PURPLE    0x5
#define BROWN    0x6
#define WHITE 0x7

void cls();
int putchar(char ch);
int puts(char* str);
void set_cur_pos(unsigned char col, unsigned char row);
void inttostr(int num, char* str);

linker.ld

Прихований текст

ENTRY (loader)
LMA = 0x00100000;
SECTIONS
{
    . = LMA;
    .multiboot ALIGN (0x1000) :   {  boot.o( .text ) }
    .text      ALIGN (0x1000) :   {  *(.text)          }
    .rodata    ALIGN (0x1000) :   {  *(.rodata*)       }
    .data      ALIGN (0x1000) :   {  *(.data)          }
    .bss :                        {  *(COMMON) *(.bss) }
    /DISCARD/ :                   {  *(.comment) }
} 

Makefile

Прихований текст

CC=gcc
CFLAGS=-m32 -Wall -fno-builtin -nostdlib -nostdinc  # -m32 Потрібно тільки на 64 бітних системах
LINKER=ld
ASM=as
kernel.bin: main.o boot.o
    $(LINKER) -m elf_i386 -T linker.ld -o kernel.bin boot.o main.o 

boot.o: boot.s
    $(ASM) -o boot.o boot.s -32

main.o: main.c multiboot.h
    $(CC) $(CFLAGS) -o main.o -c  main.c 

Як асемблер я використав gas. Код розрахований для компіляції під Unix подібними ОС, тому що тип вихідного файлу elf. Хоча може хтось зможе побудувати його і під Windows.

При завантаженні в Grub 2 запускати командою multiboot.
В Grub Legacy по-ідеї з допомогою kernel.

Я думаю тут все зрозуміло, але якщо виникнути питання пишіть.
Опис Multiboot доступний тут http://www.gnu.org/software/grub/manual … iboot.html.

P.S Завантажувач налаштовує сегментну адресацію не до кінця тому перед перевизначенням будь якого сегментного регістру треба створити свій GDT.

Post's attachments

kernel.tar 20 kb, 157 downloads since 2013-10-02 

Нехай буде з тобою сила!