Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
iakovlev.org

bkerndev - boot

 Bran's Kernel Development
 A tutorial on writing kernels
 Version 1.0 (Feb 6th, 2005)
 By: Brandon Friesen
 

Разработка ядра - нетривиальная задача . Это как проверка на умение создать софт и интерфейс для управления железом . Ядро - это центральная часть операционных систем - центр управления ресурсами компьютера .

Одним из важнейших ресурсов является процессор - на нем выделяется время для операций , прерываний , задач и т.д. Через него реализуется многозадачность , которая подразумевает наличие шедулятора (sheduler) , например шедулятор под названием 'Round Robin' - простейший вариант , когда имеется список процессов . Более сложные шедуляторы имеют приоритеты , от которых зависит время выполнения процесса .

Другим важнейшим ресурсом является память . Для эффективной работы процессор должен уметь использовать память для хранения промежуточных данных .

Следующим важнейшим ресурсом являются прерывания - Interrupt Requests (IRQs), которые представляют из себя специальные сигналы , например от клавиатуры или харда , посланные процессору для того , чтобы тот приготовился от них читать данные .

Следующим ресурсом являются шины данных - Direct Memory Access (DMA) channels. Они управляют потоками данных памяти . DMA позволяют переводить данные без использования ЦПУ

Еще одним ресурсом являются порты ввода-вывода . Устройство может быть прочитано с помощью таких портов .

В данном руководстве будет показано , как создать простейшее ядро , которое может быть загружено с помощью GRUB . Будут проинициализированы Global Descriptor Table (GDT) , Interrupt Descriptor Table (IDT) . Будут созданы процедуры , обслуживающие прерывания - Interrupt Service Routines (ISRs) . Будет проинициализирована клавиатура .

Автор все тестировал на следующей конфигурации : NASM + DJGPP + Windows . Я переписал загрузчик на GNU ASM под 3-й федорой . Вам может пригодиться утилита intel2gas , которая перводит формат INTEL ASM в гну-шный формат AT .

Автор предлагает иметь в наличие второй компьютер для тестирования . Существуют более оптимальные варианты отладки - например , я отлаживался на VMWARE 5.0 .

После того как произошла первичная загрузка , загрузчик обычно передает управление стартовой функции ядра (main()) . Эта часть , равно как и инициализация стека , загрузка GDT, IDT , как правило делается на ассемблере . Все остальное пишется на си .

В ассемблерном файле создается стек размером 8 КБ . Он используется си-шными функциями для передачи параметров . Он также используется для хранения локальных переменных внутри этих функций . Глобальные переменные хранятся в секторе данных . В самом начале ассемблерного файла также необходимо проинициализировать глобальные физические адреса для линковочного скрипта .


 .code32
 .globl start
 start: 
 	mov $(Stack + 8192), %esp    
 	jmp stublet
 
 # Эта часть должна быть выравнена на  4 byte
 .align 4
 mboot: 
     # Multiboot macros 
 .set  MULTIBOOT_PAGE_ALIGN, 1<<0
 .set  MULTIBOOT_MEMORY_INFO, 1<<1
 .set  MULTIBOOT_AOUT_KLUDGE, 1<<16
 .set  MULTIBOOT_HEADER_MAGIC, 0x1BADB002
 .set  MULTIBOOT_HEADER_FLAGS , MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO 
 	| MULTIBOOT_AOUT_KLUDGE
 .set  MULTIBOOT_CHECKSUM  , -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
 .extern code, bss, end
 
     # GRUB Multiboot header
 .long MULTIBOOT_HEADER_MAGIC
 .long MULTIBOOT_HEADER_FLAGS
 .long MULTIBOOT_CHECKSUM
 
     # глобальные физические адреса для линковочного скрипта
 .long mboot
 .long code
 .long bss
 .long end
 .long start
 
 stublet: 
 .extern main
     call main
 right:    
     jmp right
 .....
 .section .bss
 .lcomm Stack, 8192               # Резервируем 8 КБ под стек
        
 

Линкер - инструмент , который берет скомпилированные обьектные файла и получает из них собственно ядро - бинарный файл kernel.img . В таком бинарном файле всегда существуют 3 секции :


 	TEXT
 	DATA
 	BSS
 
TEXT - хранится код . DATA - инициализированные данные . BSS - неинициализированные данные . BSS - это виртуальная секция : в самом бинарнике ее нет , она создается в момент загрузки ядра .

Для линковки линкер использует специальный скрипт . Скрипт имеет 3 главных ключевых слова :

OUTPUT_FORMAT - тип файла - бинарный

ENTRY - указывает обьектный файл , который в списке линковки идет первым .

phys - это не ключевое слово , это просто переменная , которая указывает , по какому адресу памяти будет загружено наше ядро - в данном случае 1 МБ

SECTIONS - определяет секции , которые выравниваются по 4 КБ - размер интеловской страницы по умолчанию


 OUTPUT_FORMAT("binary")
 ENTRY(start)
 phys = 0x00100000;
 SECTIONS
 {
   .text phys : AT(phys) {
     code = .;
     *(.text)
     . = ALIGN(4096);
   }
   .data : AT(phys + (data - code))
   {
     data = .;
     *(.data)
     . = ALIGN(4096);
   }
   .bss : AT(phys + (bss - code))
   {
     bss = .;
     *(.bss)
     . = ALIGN(4096);
   }
   end = .;
 }
 
 
Makefile для получения ядра :

 CFLAGS  = -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions 
            -nostdinc -fno-builtin -I./include -c 
 LDFLAGS = -T link.ld
 OBJS    = obj/start.o obj/main.o  obj/scrn.o obj/gdt.o obj/idt.o obj/isrs.o obj/irq.o 
           obj/timer.o obj/kb.o
 CC      = gcc -pipe
 
 #default: clean all
 
 all: kernel.img
 
 obj/start.o: boot/start.s
 	as -o obj/start.o boot/start.s 
 obj/main.o: kernel/main.c
 	${CC} -o obj/main.o -c kernel/main.c ${CFLAGS}
 obj/scrn.o: kernel/scrn.c
 	${CC} -o obj/scrn.o -c kernel/scrn.c ${CFLAGS}
 obj/gdt.o: kernel/gdt.c
 	${CC} -o obj/gdt.o -c kernel/gdt.c ${CFLAGS}
 obj/idt.o: kernel/idt.c
 	${CC} -o obj/idt.o -c kernel/idt.c ${CFLAGS}
 obj/isrs.o: kernel/isrs.c
 	${CC} -o obj/isrs.o -c kernel/isrs.c ${CFLAGS}
 obj/irq.o: kernel/irq.c
 	${CC} -o obj/irq.o -c kernel/irq.c ${CFLAGS}
 obj/timer.o: kernel/timer.c
 	${CC} -o obj/timer.o -c kernel/timer.c ${CFLAGS}
 obj/kb.o: kernel/kb.c
 	${CC} -o obj/kb.o -c kernel/kb.c ${CFLAGS}
 	
 kernel.img: ${OBJS}
 	ld ${LDFLAGS} -o build/kernel.img ${OBJS}
 
 clean:
 	rm -f -v obj/*.o *.img
 	rm  build/kernel.img
 

Архив исходников лежит тут (GNU ASM)

Архив исходников лежит тут (NASM)

Функция main() - стартовая точка ядра , она находится в main.c . Имеется хидер - system.h - в котором прописаны прототипы глобальных функций . Функция main() ничего не возвращает , она оканчивается как правило бесконечным циклом .


 #include < system.h>
 void *memcpy(void *dest, const void *src, size_t count)
 {
     const char *sp = (const char *)src;
     char *dp = (char *)dest;
     for(; count != 0; count--) *dp++ = *sp++;
     return dest;
 }
 void *memset(void *dest, char val, size_t count)
 {
     char *temp = (char *)dest;
     for( ; count != 0; count--) *temp++ = val;
     return dest;
 }
 unsigned short *memsetw(unsigned short *dest, unsigned short val, size_t count)
 {
     unsigned short *temp = (unsigned short *)dest;
     for( ; count != 0; count--) *temp++ = val;
     return dest;
 }
 size_t strlen(const char *str)
 {
     size_t retval;
     for(retval = 0; *str != '\0'; str++) retval++;
     return retval;
 }
 unsigned char inportb (unsigned short _port)
 {
     unsigned char rv;
     __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
     return rv;
 }
 void outportb (unsigned short _port, unsigned char _data)
 {
     __asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
 }
 void main()
 {
 
     gdt_install();
     idt_install();
     isrs_install();
     irq_install();
     init_video();
     timer_install();
     	
     keyboard_install();
 
     __asm__ __volatile__ ("sti");
 
     ........
     	
     for (;;);
     
 }
 

Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье
Anton
  На вашем сайте я узнал ряд интересных подробностей о программирование 
в защищенном режиме. Спасибо.
2005-12-20 17:59:43
Антон ( ино�
  Very Good
Спасибо што подсказали, что есть порт LD под Windu!!! 
Не знал. Очень пригодится. Исходники ld можно где-нибудь отыскать (на си)? 
ant-str@yandex.ru
2006-01-26 02:47:41
Яковлев Се�
  Если имеется ввиду линуксовый линкер ,то он входит в состав пакета binutils
binutils версии 2.15 например весит 11 метров в архиве
Там кроме ld входят также :
ar
as
gprof
objdump
и т.д.
2006-01-26 18:57:37
Антон
  Thanx
2006-04-11 03:16:14