5 DERECHA

Operating System (Hardware Initialization) 본문

Operating System

Operating System (Hardware Initialization)

kay30 2023. 4. 11. 20:45

1. Concept

Process and Thread are fundamental concepts in computer science and operating systems, used to manage the execution of tasks or programs in a computer system.


(1) Process

    A process can be thought of as an instance of a program in execution. It consists of a program code, data, and system resources such as memory, file handles, and CPU time. A process has its own memory space and runs in its own address space, which is isolated from other processes. Processes are typically independent and do not share memory with other processes, which provides a high level of isolation and security. Each process has its own state, including variables, registers, and program counter, which determines the current execution point within the process.

<code>

 

 

(2) Thread

     A thread is a smaller unit of a process that can be scheduled for execution independently. Threads share the same memory space as the parent process, including code, data, and system resources. This means that threads within the same process can directly access and modify the same variables and data structures, making communication between threads faster compared to inter-process communication (IPC) mechanisms used between processes. Threads are sometimes referred to as "lightweight processes" as they do not require the same level of resources as a full process.

<code>

 

   Processes and threads have their own advantages and use cases. Processes provide strong isolation between tasks, making them suitable for tasks that require high security, fault tolerance, and robustness. Threads, on the other hand, are useful for tasks that require concurrent execution, parallelism, and efficient communication between different parts of a program. Threads can also improve the responsiveness and performance of a program by allowing tasks to be executed concurrently, taking advantage of multi-core processors.

 

(3) Multi thread

 

<Code>

 

(4) RTOS

Multi-threading with Real-Time Operating Systems (RTOS) allows for concurrent execution of tasks, where each thread represents a specific task or functionality. RTOS provides mechanisms for managing multi-threading with time-constraints to ensure that tasks are executed within specified deadlines. Here are some key aspects of multi-threading with time-constraints in RTOS:

1) Task Prioritization: RTOS allows tasks to be assigned priorities, where tasks with higher priorities are scheduled to run before tasks with lower priorities. This enables fine-grained control over task execution, ensuring that time-critical tasks are given higher priority and executed in a timely manner.

2) Task Scheduling: RTOS provides scheduling mechanisms, such as preemptive scheduling, where tasks can be interrupted and rescheduled based on their priorities. This allows for efficient utilization of system resources and ensures that higher priority tasks can interrupt lower priority tasks when needed, meeting time-constraints.

3) Deadline Management: RTOS allows for specifying deadlines for tasks, which are the maximum allowed execution times. RTOS monitors task execution times and ensures that tasks are completed within their specified deadlines. If a task exceeds its deadline, the system can take appropriate actions, such as triggering an error or taking corrective measures.

4) Time-Based Triggers: RTOS allows tasks to be triggered based on time-based events or timers. This enables tasks to be scheduled to run at specific intervals or at particular times, ensuring that time-critical tasks are executed at the right time.

5) Resource Management: RTOS provides synchronization primitives like mutexes, semaphores, and message queues for safe and efficient sharing of resources among tasks. This prevents conflicts and ensures proper coordination among tasks, avoiding delays that could violate time-constraints.

6) Context Switching: RTOS allows for rapid context switching between tasks, enabling concurrent execution of multiple tasks. Context switching is typically fast and deterministic in RTOS, ensuring that tasks can be switched quickly without introducing additional delays.

6) Real-time Analysis: RTOS often provides real-time analysis tools, such as profiling and tracing, to monitor and analyze the system's real-time performance. These tools help developers optimize the system's real-time behavior and ensure that time-constraints are met.

In summary, multi-threading with time-constraints in RTOS involves task prioritization, scheduling, deadline management, time-based triggers, resource management, context switching, and real-time analysis. These mechanisms ensure that tasks are executed within specified deadlines, meeting the real-time constraints of the application and ensuring reliable and timely operation.

 

(5) Hardware Initialization

1) GDT => for segementation

    GDT (Global Descriptor Table) : GDT is a data structure used by x86 processors to define memory segments and their attributes, such as base address, limit, and access permissions. During hardware initialization, the GDT is typically set up by the operating system or bootloader to provide memory protection and segmentation for software running in protected mode.

2) IDT

    IDT (Interrupt Descriptor Table) : IDT is a data structure used by x86 processors to define interrupt handlers, which are routines that are executed in response to hardware interrupts or software-generated interrupts (exceptions). During hardware initialization, the IDT is typically set up by the operating system or bootloader to handle various interrupts and exceptions that may occur during system operation.

3) PIC

 

4) PIT

 

5) FPU

 

 

2. 실습 진행

 

3. Data Structure

(1) MultiBootInfo

</MultiBoot.h>

struct multiboot_info
{
	/* Multiboot info version number */
	uint32_t flags;

	/* Available memory from BIOS */ // 메모리 영역 정보! 
	uint32_t mem_lower;
	uint32_t mem_upper;

	/* "root" partition */
	uint32_t boot_device;

	/* Kernel command line */
	char *cmdline;

	/* Boot-Module list */
	uint32_t mods_count;
	Module *Modules;

	union
	{
		AOUTSymbolTable AOUTTable;
		ELFHeaderTable ELFTable;
	} SymbolTables;

	/* Memory Mapping buffer */ // 메모리 매핑 정보! => 메모리 특정 블록을 사용할 수 있는지 파악 가능
	uint32_t mmap_length;
	uint32_t mmap_addr;

	/* Drive Info buffer */
	uint32_t drives_length;
	drive_info * drives_addr;

	/* ROM configuration table */
	ROMConfigurationTable *ConfigTable;

	/* Boot Loader Name */
	char* boot_loader_name;

	/* APM table */
	APMTable *APMTable;

	/* Video */
	VbeInfoBlock *vbe_control_info;
	VbeModeInfo *vbe_mode_info;
	uint16_t vbe_mode;
	uint16_t vbe_interface_seg;
	uint16_t vbe_interface_off;
	uint16_t vbe_interface_len;
};
typedef struct multiboot_info multiboot_info_t;

(2) GDT Descriptor

: 8 Byte which is consisted of baseLow, baseMiddle, baseHigh fields that can get base address, segment limit and grand fields taht can get segementaion size.

</CPU/GDT.h>

struct gdt_descriptor {

	//! bits 0-15 of segment limit
	uint16_t		limit;

	//! bits 0-23 of base address
	uint16_t		baseLo;
	uint8_t			baseMid;

	//! descriptor access flags
	uint8_t			flags;

	uint8_t			grand;

	//! bits 24-32 of base address
	uint8_t			baseHi;
};

(3) GDTR

: GDTR let CPU knows where the GDT is located.

</CPU/GDT.cpp>

//! processor gdtr register points to base of gdt. This helps
//! us set up the pointer
struct gdtr {

	//! size of gdt
	uint16_t		m_limit;

	//! base address of gdt
	uint32_t		m_base;
};

(4) GDT Descriptor flag

<~/defines.h>

//! set access bit
#define I86_GDT_DESC_ACCESS			0x0001			//00000001

//! descriptor is readable and writable. default: read only
#define I86_GDT_DESC_READWRITE			0x0002			//00000010

//! set expansion direction bit
#define I86_GDT_DESC_EXPANSION			0x0004			//00000100

//! executable code segment. Default: data segment
#define I86_GDT_DESC_EXEC_CODE			0x0008			//00001000

//! set code or data descriptor. defult: system defined descriptor
#define I86_GDT_DESC_CODEDATA			0x0010			//00010000

//! set dpl bits
#define I86_GDT_DESC_DPL			0x0060			//01100000

//! set "in memory" bit
#define I86_GDT_DESC_MEMORY			0x0080			//10000000
/**	gdt descriptor grandularity bit flags	***/

//! masks out limitHi (High 4 bits of limit)
#define I86_GDT_GRAND_LIMITHI_MASK		0x0f			//00001111

//! set os defined bit
#define I86_GDT_GRAND_OS			0x10			//00010000

//! set if 32bit. default: 16 bit
#define I86_GDT_GRAND_32BIT			0x40			//01000000

//! 4k grandularity. default: none
#define I86_GDT_GRAND_4K			0x80			//10000000

 

 

 

4. Function Detail

(1) GDT  setting & GDTR register load

</CPU/GDT.cpp>

//GDT 초기화 및 GDTR 레지스터에 GDT 로드
int GDTInitialize()
{
	//GDTR 레지스터에 로드될 _gdtr 구조체의 값 초기화
	//_gdtr 구조체의 주소는 페이징 전단계이며 실제 물리주소에 해당 변수가 할당되어 있다.
	//디스크립터의 수를 나타내는 MAX_DESCRIPTORS의 값은 5이다.
	//NULL 디스크립터, 커널 코드 디스크립터, 커널 데이터 디스크립터, 유저 코드 디스크립터
	//유저 데이터 디스크립터 이렇게 총 5개이다.
	//디스크립터당 6바이트이므로 GDT의 크기는 30바이트다.
	_gdtr.m_limit = (sizeof(struct gdt_descriptor) * MAX_DESCRIPTORS) - 1;
	_gdtr.m_base = (uint32_t)&_gdt[0];

	//NULL 디스크립터의 설정
	gdt_set_descriptor(0, 0, 0, 0, 0);

	//커널 코드 디스크립터의 설정
	gdt_set_descriptor(1, 0, 0xffffffff,
		I86_GDT_DESC_READWRITE | I86_GDT_DESC_EXEC_CODE | I86_GDT_DESC_CODEDATA |
		I86_GDT_DESC_MEMORY, I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT |
		I86_GDT_GRAND_LIMITHI_MASK);

	//커널 데이터 디스크립터의 설정
	gdt_set_descriptor(2, 0, 0xffffffff,
		I86_GDT_DESC_READWRITE | I86_GDT_DESC_CODEDATA | I86_GDT_DESC_MEMORY,
		I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);

	//유저모드 디스크립터의 설정
	gdt_set_descriptor(3, 0, 0xffffffff,
		I86_GDT_DESC_READWRITE | I86_GDT_DESC_EXEC_CODE | I86_GDT_DESC_CODEDATA |
		I86_GDT_DESC_MEMORY | I86_GDT_DESC_DPL, I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT |
		I86_GDT_GRAND_LIMITHI_MASK);

	//유저모드 데이터 디스크립터의 설정
	gdt_set_descriptor(4, 0, 0xffffffff, I86_GDT_DESC_READWRITE | I86_GDT_DESC_CODEDATA | I86_GDT_DESC_MEMORY | I86_GDT_DESC_DPL,
		I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);

	//GDTR 레지스터에 GDT 로드
	InstallGDT();

	return 0;
}
//! install gdtr
static void InstallGDT () {
#ifdef _MSC_VER
	_asm lgdt [_gdtr]
#endif
}
//! Setup a descriptor in the Global Descriptor Table
void gdt_set_descriptor(uint32_t i, uint64_t base, uint64_t limit, uint8_t access, uint8_t grand)
{
	if (i > MAX_DESCRIPTORS)
		return;

	//! null out the descriptor
	memset ((void*)&_gdt[i], 0, sizeof (gdt_descriptor));

	//! set limit and base addresses
	_gdt[i].baseLo	= uint16_t(base & 0xffff);
	_gdt[i].baseMid	= uint8_t((base >> 16) & 0xff);
	_gdt[i].baseHi	= uint8_t((base >> 24) & 0xff);
	_gdt[i].limit	= uint16_t(limit & 0xffff);

	//! set flags and grandularity bytes
	_gdt[i].flags = access;
	_gdt[i].grand = uint8_t((limit >> 16) & 0x0f);
	_gdt[i].grand |= grand & 0xf0;
}

'Operating System' 카테고리의 다른 글

Interview Questions  (0) 2023.10.22
Operating System (Memory Manager)  (1) 2023.04.17
Operating System  (0) 2023.03.06