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
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Rodriguez 3...2351 
 M.Pilgrim->Часть 2...1380 
 Rodriguez 6...1379 
 Httpd-> История Ap...1379 
 FAQ...1379 
 Ext4 FS...1378 
 Cluster 2...1378 
 ground Up...1378 
 Perl 8...1378 
 0.01->DOC-> Коммен...1378 
 Ulrich Drepper...1378 
 Stewens -> IPC 9...1378 
 C++ Patterns 2...1378 
 Erlang 3...1378 
 Go Web ...1377 
 Linux Assembler Tutorial...1377 
 Rubni-Corbet -> Глав...1377 
 Ethreal 4...1377 
 Robert Love 2...1377 
 Django...1377 
 
  01.01.2024 : 3621733 посещений 

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

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

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

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

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

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