Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 OS
 osjournal 
 Protected Mode 
 Hardware 
 Kernels
  Dark Fiber
  BOS
  QNX
  OS Dev
  Lecture notes
  MINIX
  OS
  Solaris
  История UNIX
  История FreeBSD
  Сетунь
NEWS
Последние статьи :
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
  SQL 30.07   
  JFS 10.06   
  B-trees 01.06   
 
TOP 20
 P.Collins...1335 
 Steve Pate 1...751 
 QT->Qt3...362 
 Trees...355 
 Python...320 
 Steve Pate 3...287 
 TCP 2...267 
 Rodriguez 6...251 
 Максвелл 3...249 
 Daniel Bovet 4...246 
 Linux Inline Assembly...244 
 MySQL & PosgreSQL...242 
 TCP 3...241 
 Rubni-Corbet -> Глав...237 
 Rodriguez 2...231 
 Mod_perl 2...229 
 Robert Love 2...229 
 UML 3...223 
 C++ Templates 4...222 
 Стивенс 9...218 
 
  01.05.2017 : 2190164 посещений 

iakovlev.org

Stupid OS

Данный проект является примером того , как трудозатраты на низкоуровневое программирование свести к минимуму. Чистого ассемблера здесь раз-два и обчелся : маленький загрузчик и немного кода для доступа к портам. Хотя совсем от ассемблера отказаться невозможно , поэтому он перекочевывает в инлайн.

Последовательность событий :
1. Инициализация GDT
2. Инициализация IDT
3. Инициализация PIC
4. Инициализация клавиатуры
5. Инициализвация таймера

GDT

8-байтовый дескриптор описывается с помощью структуры gdt_str_tag :

 typedef struct gdt_str_tag
 {
 	unsigned short int seg_limit_low;       //segment limit - 2 байта
 	unsigned short int base_low;		//Base Address - 2 байта
 	unsigned char base_mid;			//Base Address - 1 байт
 	seg_t seg_type:4;			//Segment Type - 4 бита
 	seg_desc_t seg_desc_type:1;		//Descriptor type (1 бит, 0 = system, 1 = code/data)
 	dpl_t dpl:2;				//Descriptor Privilege level (2 бита)
 	present_t present:1;			//Segment present (1 бит)
 	unsigned char seg_limit_high:4;		//segment limit 16:19 (4 бита)
 	unsigned char gran_def_op:4;		//avl (1 бит)
 						//reserved = 0 (1 бит)
 						//D/B(default operation size / big) (1 бит)
 						//Granularity (1 бит)
 						//Для защищенного режима = 0xC 
 	unsigned char base_high;		//Base Address - 1 байт
 }gdt_st_t;
 
Заполняем поля :

 	gdt_temp.seg_limit_low 		= 0x0FFF;	//Code Descriptor	
 	gdt_temp.base_low 		= 0x0000;
 	gdt_temp.base_mid 		= 0x00;
 	gdt_temp.seg_type		= 0xA;
 	gdt_temp.seg_desc_type 		= CODE_DATA;
 	gdt_temp.dpl 			= RING_0;
 	gdt_temp.present 		= PRESENT;
 	gdt_temp.seg_limit_high 	= 0x0;
 	gdt_temp.gran_def_op 		= GDO;
 	gdt_temp.base_high 		= 0x00;
 
Для дескриптора данных все то же самое , кроме :

 	gdt_temp.seg_type		= 0x2;
 
Адрес таблицы GDT - GDT_BASE=0x6000. Таблица состоит из 256 дескрипторов , первый - нулевой , второй - кодовый , третий-данные, остальные - также нулевые.

Для загрузки GDT в регистр GDTR создадим структуру :


 typedef struct gdtr_str_tag
 {
 	unsigned short int gdt_length;
 	unsigned short int gdt_base_low;
 	unsigned short int gdt_base_high;
 }gdtr_st_t;
 
Загрузка :

 	gdtr.gdt_length = (unsigned short int) 256 * 8;
 	gdtr.gdt_base_low = (unsigned short int) GDT_BASE_LOW;
 	gdtr.gdt_base_high = (unsigned short int) GDT_BASE_HIGH;
 	asm("lgdt (%0)": :"p" (&gdtr));
 

IDT

Опишем исключение с помощью структуры и создадим массив из 32 таких структур :

 typedef struct exceptiont_st_tag
 {
 	sint number;
 	int (* handler)();
 }exception_st_t;
 
 extern exception_st_t exceptions[32];
 
Массив exception_st_t описан в файле handler.c:

 exception_st_t exceptions[32]=
 {
         {0, ÷_error},
         {1, &debug},
         {2, &nmi_interrupt},
 		..........
         {30, &reserved},
         {31, &reserved}
 };
 
При возникновении исключения указатель exception_st_t->handler приводит куда надо - а именно в функию типа :

 int divide_error()
 {
 	kprintf("divide error exception\n", 0xF);
 	while(1);
 	return 0;
 }
 
Произведем загрузку IDT начиная с адреса IDTBASE 0x6800:

 	for(lv0 = 0; lv0 <= 31; lv0++)
 	{
 	load_idt_entry(exceptions[lv0].number,
 					(uint)exceptions[lv0].handler,
 					CS_SELECTOR,
 					TRAP_GATE|PRESENT|RING_0|BITS_32);
 	}
 
 
Внутренний дескриптор IDT опишем с помощью 6-байтовой структуры

 typedef struct idt_st_tag
 {
 	usint loffset;		// 2 байта
 	usint selector;		// 2 байта
 	byte unused;		// 1 байт
 	byte options;		
 				/*	constant:5;	 5 бит
 					 dpl:2;		 2 бит
 					 present:1;	 1 бит		*/
 
 	usint uoffset; 		// 2 bytes	
 }idt_st_t;
 
Загрузка регистра IDTR :

 	idtr.limit = (usint) (34 * 8);
 	idtr.lowbase = (usint) IDT_LOWBASE;
 	idtr.highbase = (usint) IDT_HIGHBASE;
 	asm("lidt (%0) ": :"p" (idtr));
 

PIC

Инициализация программируемого контроллера необходима для обслуживания хардварных прерываний. Определены хардварные хэндлеры в порядке приоритета :

 #define TIMER 0x0       	- системный таймер
 #define KEYBOARD 0x1    	- клавиатура
 #define SLAVE 0x2       	- вторичный PIC 
 #define TTY1 0x3        	- COM2 
 #define TTY2 0x4        	- COM1
 #define XT_WINCHESTER 0x5   	- LPT2
 #define FLOPPY 0x6		- floppy
 #define PRINTER 0x7		- printer
В последующем будут проинициализированы клавиатура с таймером. Для их инициализации будет вызвана функция enable_irq(byte irq_no), где в качестве параметра будет стоять нужный хэндлер.

Клавиатура

Для загрузки клавиатуры нужно загрузить дескриптор в таблице IDT со следующими параметрами :

 	load_idt_entry(33,(uint)&keyboard_handler,CS_SELECTOR,INT_GATE|PRESENT|BITS_32);
 
после чего разрешить прерывание :

 	enable_irq(KEYBOARD);
 
В качестве одного из параметров этой загрузки выступает функция keyboard_handler() - фактически это обработчик нажимаемых клавиш.

Таймер

Для инициализации таймера нужно загрузить дескриптор в таблице IDT со следующими параметрами :

      load_idt_entry(32,(uint)&timer_handler,CS_SELECTOR,TRAP_GATE|PRESENT|RING_0|BITS_32);
 
после чего разрешить прерывание :

 	 enable_irq(TIMER);
 
На системный таймер повешен хэндлер - timer_handler(). В нем обрабатывается событие - переполнение переменной , при котором на экране вы увидите появление очередного символа - "точки".

Загрузчик работает из-под граб-а.

Исходники лежат тут.

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

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

 Автор  Комментарий к данной статье