Хочу поділитись з колективом 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 attachmentskernel.tar 20 kb, 459 downloads since 2013-10-02