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
 Go Web ...825 
 Httpd-> История Ap...517 
 2.0-> Linux IP Networking...438 
 MySQL & PosgreSQL...380 
 Trees...378 
 Secure Programming for Li...369 
 Assembler...304 
 TCP 2...279 
 Secure Programming for Li...270 
 Steve Pate 3...269 
 Mod_perl 1...263 
 Cluster 3...262 
 Ethreal 1...256 
 Максвелл 3...254 
 Advanced Bash Scripting G...244 
 Python...236 
 Daniel Bovet 5...231 
 Linux Inline Assembly...231 
 Rubni-Corbet -> Глав...230 
 Steve Pate 1...229 
 
  01.06.2017 : 2215600 посещений 

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(). В нем обрабатывается событие - переполнение переменной , при котором на экране вы увидите появление очередного символа - "точки".

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

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

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

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

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