For more in depth concepts visit:
1 idt.c
Similar to the gdt, we have to set the interrupt descriptor.
#include <system.h>
/*
* IDT Entry
*/
struct idt_entry {
unsigned short base_low;
unsigned short sel;
unsigned char zero;
unsigned char flags;
unsigned short base_high;
} __attribute__((packed));
struct idt_ptr {
unsigned short limit;
unsigned int base;
} __attribute__((packed));
struct idt_entry idt[256];
struct idt_ptr idtp;
extern void idt_load();
/*
* idt_set_gate
* Set an IDT gate
*/
void
set_idt_gate(
unsigned char num,
unsigned long base,
unsigned short sel,
unsigned char flags
) {
idt[num].base_low = (base & 0xFFFF);
idt[num].base_high = (base >> 16) & 0xFFFF;
idt[num].sel = sel;
idt[num].zero = 0;
idt[num].flags = flags;
}
/*
* idt_install
* Install the IDTs
*/
void
idt_install() {
idtp.limit = (sizeof(struct idt_entry) * 256) - 1;
idtp.base = &idt;
memset(&idt, 0, sizeof(struct idt_entry) * 256);
idt_load();
}Data Structures
IDT Entry Structure:
struct idt_entry {
unsigned short base_low;
unsigned short sel;
unsigned char zero;
unsigned char flags;
unsigned short base_high;
} __attribute__((packed));
base_low: Lower 16 bits of the handler function address.sel: Code segment selector in GDT or LDT.zero: Always set to 0.flags: Type and attributes of the interrupt gate.base_high: Upper 16 bits of the handler function address.__attribute__((packed)): Ensures there is no padding between the members of the structure.
IDT Pointer Structure:
struct idt_ptr {
unsigned short limit;
unsigned int base;
} __attribute__((packed));
limit: Size of the IDT - 1 (in bytes).base: Address of the first element in the IDT.
Global Variables
IDT and IDT Pointer:
struct idt_entry idt[256];
struct idt_ptr idtp;
idt[256]: Array of IDT entries. The x86 architecture supports up to 256 interrupts.idtp: The IDT pointer, which holds the base address and size of the IDT.
External Function
idt_load:
extern void idt_load();
- This external function is implemented in assembly. It loads the IDT using the
lidtinstruction.
Functions:
set_idt_gate:
void set_idt_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags) {
idt[num].base_low = (base & 0xFFFF);
idt[num].base_high = (base >> 16) & 0xFFFF;
idt[num].sel = sel;
idt[num].zero = 0;
idt[num].flags = flags;
}
num: Index of the IDT entry.base: Address of the interrupt handler.sel: Segment selector.flags: Type and attributes.- This function sets up a specific IDT entry with the provided base address, selector, and flags.
idt_install:
void idt_install() {
idtp.limit = (sizeof(struct idt_entry) * 256) - 1;
idtp.base = &idt;
memset(&idt, 0, sizeof(struct idt_entry) * 256);
idt_load();
}
idtp.limit: Set to the size of the IDT in bytes minus 1.idtp.base: Set to the address of theidtarray.memset(&idt, 0, sizeof(struct idt_entry) * 256): Initialize the entire IDT with zeros.idt_load(): Load the IDT using thelidtinstruction (implemented in assembly).
2 idt_asm.asm
The function idt_load will be implemented here, which is called in the idt_install file.
; Interrupt Descriptor Table
global idt_load
extern idtp
idt_load:
lidt [idtp]
ret
3 Modify main.c to call idt_install()
We did all the setup, its time to call the idt_install() from the kernel main function:
int
main() {
gdt_install();
............................
idt_install();
............................
init_video();
puts("Hello world!\n");
for (;;);4 Modify Makefile
Modify the Makefile to build newly added source files.

Join the discussion
Sign in with your account to post comments, reply to others, and participate in the conversation.
Login to Comment