Loaded IDT!

Many code changes, many undocumented. Documentation and cleanup is next.

Fixed a lot of bugs related to IDT structure. Changed the IDT paradigm
to be dynamically written isntead of statically to account for nobits on
that section.
Also added a gdb remote debugger automatic script, for simplicity in
debugging.
This commit is contained in:
lordtet 2025-06-28 00:14:42 -04:00
parent fbef354410
commit 561c7f9fa7
10 changed files with 72 additions and 28 deletions

6
connect_gdb.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
i686-elf-gdb build/ukern.elf \
-ex "target remote localhost:1234" \
-ex "break start" \
-ex "continue"

View file

@ -3,24 +3,24 @@
#include <stdint.h>
typedef struct InterruptDescriptor_s {
uint16_t offset_1;
uint16_t offset_lo;
uint16_t selector;
uint8_t reserved;
uint8_t attributes;
uint16_t offset_2;
uint16_t offset_hi;
} InterruptDescriptor_t;
typedef struct IDTR_s {
uint16_t size;
InterruptDescriptor_t* IDT;
} IDTR_t;
} __attribute__((packed)) IDTR_t;
extern IDTR_t idtr;
extern InterruptDescriptor_t* idt_start;
extern char num_interrupts;
extern InterruptDescriptor_t idt_start;
extern unsigned char num_interrupts;
void setup_idt();
void write_descriptors();
void load_idt();
extern void load_idt();
#endif

View file

@ -1,10 +1,12 @@
#ifndef INTERRUPTHANDLERS_H
#define INTERRUPTHANDLERS_H
#include <stdint.h>
extern void* isr_ptrs;
extern void (*isr_ptrs[])(void);
//Struct is built "backwards" since it is pushed in this order.
typedef struct StateSnapshot_s {
uint32_t eax, ecx, edx, ebx, esp, esi, edi;
uint32_t edi, esi, esp, ebx, edx, ecx, eax;
uint32_t interrupt_id, error_code;
uint32_t eip, cs, eflags;
} StateSnapshot_t;

View file

@ -1,15 +1,19 @@
%define NUM_INTERRUPTS 32
global idtr, idt_start, num_interrupts
section .idtr
%define NUM_INTERRUPTS 255
global idtr, idt_start, num_interrupts, load_idt
section .text
load_idt:
lidt [idtr]
ret
section .idtr align=8
num_interrupts:
db NUM_INTERRUPTS
idtr:
;Normally, the size would be the size of the whole table, but i'm only defining 32 interrupts for now.
;dw idt_end - idt_start
dw NUM_INTERRUPTS * 8
dd idt_start
;IDTR looks like the size (minus 1) and then the pointer to the start of it.
dw 0
dd 0
section .idt nobits
idt_start:
resb NUM_INTERRUPTS * 8
idt_end:
resb (NUM_INTERRUPTS+1) * 8

View file

@ -50,7 +50,8 @@ section .gdt_sect
db 0
db 0b10001001
dw 0
gdt_end:
gdtr:
dw gdtr - gdt - 1
dw gdt_end - gdt - 1
dd gdt

View file

@ -1,18 +1,35 @@
#include "idt.h"
#include "interrupt_handlers.h"
void setup_idt() {
idtr.size = (sizeof(InterruptDescriptor_t) * 256) - 1;
idtr.IDT = &idt_start;
write_descriptors();
load_idt();
}
void write_descriptors() {
for(int i = 0; i < num_interrupts; i++) {
for(int i = 0; i <= num_interrupts; i++) {
uint32_t current_isr = (uint32_t)isr_ptrs[i];
InterruptDescriptor_t* current_idt_entry = idtr.IDT + (i*8);
// Offset bits 0-15
current_idt_entry->offset_lo = current_isr & 0xFFFF;
current_idt_entry->offset_hi = current_isr >> 16;
current_idt_entry->selector = 0x08; // GDT index = 1 (kernel code seg), TI = 0 (pull from GDT, not LDT), RPL = 0 (ring 0)
//Attributes is a complex field. Lets break it down:
//First 4 bits is the gate type. Task, interrupt, trap.
//bit 44 is a zero
//Bits 45-46 is DPL - or what rings can access the interrupt via the INT instruction.
if(i < 32)
//All interrupt gates, only R0 can access.
current_idt_entry->attributes = 0b10001110;
else
//All interrupt gates, all rings can use these ints.
current_idt_entry->attributes = 0b11101110;
}
}
void load_idt() {
return;
}

View file

@ -34,7 +34,7 @@ isr_%1:
%assign j 0
%rep 32
%rep 255
isr_ %+ j:
ISR_ENTRY j
%assign j j+1
@ -42,7 +42,7 @@ isr_%1:
; Generate a table of pointers that point to each of our ISRs. This will be accessed from C to setup our IDT.
isr_ptrs:
%assign i 0
%rep 32
%rep 255
dd isr_ %+ i
%assign i i+1
%endrep

View file

@ -76,7 +76,6 @@ void vga_printdec(uint32_t out) {
void vga_printf(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
while(*fmt) {
if(*fmt == '%') {
fmt++;

View file

@ -30,6 +30,11 @@
*/
void i_to_str(uint32_t num, char* buf, int size, int radix) {
//null terminate the string
if(num == 0){
buf[0] = '0';
buf[1] = '\0';
return;
}
buf[--size] = '\0';
while(size > 0 && (num) != 0){
int isolated_num = num % radix;

View file

@ -4,15 +4,24 @@
#include "kio.h"
#include "kttools.h"
#include "kmultiboot.h"
#include "idt.h"
//finally, main.
void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
{
//Hello C! Let's get to work in cleaning up our environment a bit and creating some safety.
//First interrupts.
vga_clear();
vga_printf("IDT base = %X", idtr.IDT);
setup_idt();
vga_printf("IDT test :)");
int x = 5;
int y = 1;
x = x / (y-1);
vga_printf("%d", x);
//wipe the screen
vga_clear();
//We're going to use this buffer as our 8char hex representation for reading mem
@ -28,5 +37,6 @@ void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
vga_printf("MEM_LOWER:%X\n", multiboot_info->mem_lower);
vga_printf("MEM_UPPER:%X\n", multiboot_info->mem_upper);
}