From fc95fb5ff6fdc2f7b1dff2440d27c2da1ee85b72 Mon Sep 17 00:00:00 2001 From: vanten-s Date: Tue, 16 Jul 2024 22:51:41 +0200 Subject: [PATCH] Added most things needed for interrupts --- Makefile | 59 +++++++++------- arch/i686/bootstrap.s | 22 ++++++ arch/i686/gdt.c | 120 ++++++++++++++++++++++++++++++++ arch/i686/interrupt.c | 86 +++++++++++++++++++++-- arch/i686/linker.ld | 4 +- arch/i686/tty.c | 6 -- include/debugging.h | 8 +++ include/kernel/interrupt.h | 14 +--- isodir/boot/grub/grub.cfg | 2 +- isodir/boot/myos.bin | Bin 10400 -> 0 bytes {include => kernel}/debugging.c | 22 ++++-- kernel/kernel.c | 17 ++--- 12 files changed, 293 insertions(+), 67 deletions(-) create mode 100644 arch/i686/gdt.c create mode 100644 include/debugging.h delete mode 100755 isodir/boot/myos.bin rename {include => kernel}/debugging.c (88%) diff --git a/Makefile b/Makefile index 53bc287..5f9211b 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,33 @@ ARCHDIR=arch/i686 CFLAGS?= +ASFLAGS?= INCLUDEDIR=include -CFLAGS:=-O2 \ +CFLAGS:=\ +-O2 \ -std=gnu99 \ -ffreestanding \ -Wall -Wextra \ -I$(INCLUDEDIR) \ $(CFLAGS) +ASFLAGS:=\ +-I$(INCLUDEDIR) \ +-I$(ARCHDIR) \ +$(ASFLAGS) + +KERNEL_OBJS=\ +kernel/kernel.o \ +kernel/debugging.o \ -KERNEL_OBJS=kernel/kernel.o LIB_OBJS=\ $(ARCHDIR)/bootstrap.o \ -$(ARCHDIR)/tty.o\ -$(ARCHDIR)/strlib.o\ -$(ARCHDIR)/interrupt.o\ +$(ARCHDIR)/tty.o \ +$(ARCHDIR)/strlib.o \ +$(ARCHDIR)/interrupt.o \ +$(ARCHDIR)/gdt.o \ OBJS=$(KERNEL_OBJS) $(LIB_OBJS) @@ -27,40 +37,37 @@ LDFLAGS=$(OBJS) \ -nostdlib \ -lgcc +.PHONY: all clean myos.iso .SUFFIXES: .c .o .s -all: - $(MAKE) run-grub-qemu +all: myos.iso clean: rm -f $(OBJS) - rm myos.bin - rm myos.iso - -debug: - mkdir build || true - cp Makefile build - cp -r isodir build - CFLAGS=-g $(MAKE) -C build debug-grub-qemu + rm -f myos.kernel + rm -f myos.iso + rm -f isodir/boot/myos.kernel .c.o: i686-elf-gcc -c $< -o $@ $(CFLAGS) .s.o: - i686-elf-as $< -o $@ + i686-elf-as $< -o $@ $(ASFLAGS) -myos.bin: $(OBJS) - i686-elf-gcc -T $(ARCHDIR)/linker.ld -o myos.bin $(LDFLAGS) - grub-file --is-x86-multiboot myos.bin +myos.kernel: $(OBJS) + i686-elf-gcc -T $(ARCHDIR)/linker.ld -o myos.kernel $(LDFLAGS) + grub-file --is-x86-multiboot myos.kernel -run-grub-qemu: myos.bin - cp myos.bin isodir/boot/myos.bin +myos.iso: myos.kernel + cp myos.kernel isodir/boot/myos.kernel grub-mkrescue -o myos.iso isodir - qemu-system-i386 myos.iso -debug-grub-qemu: myos.bin - cp myos.bin isodir/boot/myos.bin - grub-mkrescue -o myos.iso isodir - qemu-system-i386 -S -gdb tcp::9000 myos.iso +debug: CFLAGS += -g -O0 +debug: ASFLAGS += -g +debug: all +run: myos.iso + qemu-system-i386 myos.iso -display curses +run-debug: debug + qemu-system-i386 -S -gdb tcp::9000 myos.iso -display curses diff --git a/arch/i686/bootstrap.s b/arch/i686/bootstrap.s index 66c98bc..ab01428 100644 --- a/arch/i686/bootstrap.s +++ b/arch/i686/bootstrap.s @@ -65,6 +65,20 @@ _start: */ mov $stack_top, %esp + cli + + call gdt_init + + movw %ax, 0x10 + movw %ds, %ax + movw %es, %ax + movw %fs, %ax + movw %gs, %ax + movw %ss, %ax + # jmp kernel + ljmp $0x08, $kernel + +kernel: /* This is a good place to initialize crucial processor state before the high-level kernel is entered. It's best to minimize the early @@ -84,8 +98,15 @@ _start: stack since (pushed 0 bytes so far), so the alignment has thus been preserved and the call is well defined. */ + + mov %esp, %edx + call kernel_main +.global keyboard_test +keyboard_test: + hlt + /* If the system has nothing more to do, put the computer into an infinite loop. To do that: @@ -106,4 +127,5 @@ _start: Set the size of the _start symbol to the current location '.' minus its start. This is useful when debugging or when you implement call tracing. */ + .size _start, . - _start diff --git a/arch/i686/gdt.c b/arch/i686/gdt.c new file mode 100644 index 0000000..f51b007 --- /dev/null +++ b/arch/i686/gdt.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include + +#define NUM_ENTRIES 3 + +struct SegmentDescriptor { + uint32_t limit; + uint32_t base; + uint8_t access_byte; + uint8_t flags; +}; + +struct GDT { + uint16_t size; + uint64_t* base; +} __attribute__((packed)); + +static uint64_t entries[NUM_ENTRIES]; +static size_t current_entry = 0; +struct GDT gdt; + +static void encodeGdtEntry(uint8_t *target, struct SegmentDescriptor source) +{ + // Check the limit to make sure that it can be encoded + if (source.limit > 0xFFFFF) { + terminal_writestring("WARNING: GDT entry has a limit ("); + print_hex_bytes(&source.limit, 4); + terminal_writestring(") that is larger than accepted."); + return; + } + + // Encode the limit + target[0] = source.limit & 0xFF; + target[1] = (source.limit >> 8) & 0xFF; + target[6] = (source.limit >> 16) & 0x0F; + + // Encode the base + target[2] = source.base & 0xFF; + target[3] = (source.base >> 8) & 0xFF; + target[4] = (source.base >> 16) & 0xFF; + target[7] = (source.base >> 24) & 0xFF; + + // Encode the access byte + target[5] = source.access_byte; + + // Encode the flags + target[6] |= (source.flags << 4); + + print_hex_bytes(target, 8); +} + +static void add_entry(struct SegmentDescriptor entry) +{ + if (current_entry == NUM_ENTRIES) { + terminal_writestring("WARNING: More GDT entries than NUM_ENTRIES.\n"); + return; + } + + uint64_t descriptor = 0; + encodeGdtEntry((uint8_t*) &descriptor, entry); + + entries[current_entry] = descriptor; + + current_entry++; +} + +static void load_gdt() +{ + gdt.size = NUM_ENTRIES * 8 - 1; + gdt.base = entries; + + for (int i = 0; i < NUM_ENTRIES; i++) { + print_hex_bytes(gdt.base + i, 8); + terminal_putchar('\n'); + } + + asm ( "lgdt %0" : : "m"(gdt) ); +} + +void gdt_init() +{ + terminal_initialize(); + struct SegmentDescriptor null; + null.limit = 0; + null.base = 0; + null.access_byte = 0; + null.flags = 0; + + terminal_writestring("Kernel Null: "); + + add_entry(null); + + terminal_putchar('\n'); + + struct SegmentDescriptor kernel_code; + kernel_code.limit = 0x000003FF; + kernel_code.base = 0x00000000; + kernel_code.access_byte = 0b10011010; + kernel_code.flags = 0b1100; + + terminal_writestring("Kernel Code: "); + + add_entry(kernel_code); + terminal_putchar('\n'); + + struct SegmentDescriptor kernel_data; + kernel_code.limit = 0x000003FF; + kernel_data.base = 0x00400000; + kernel_data.access_byte = 0b10010010; + kernel_data.flags = 0b1100; + + terminal_writestring("Kernel Data: "); + + add_entry(kernel_data); + terminal_putchar('\n'); + + load_gdt(); +} diff --git a/arch/i686/interrupt.c b/arch/i686/interrupt.c index 0ec6ef9..96c7b7a 100644 --- a/arch/i686/interrupt.c +++ b/arch/i686/interrupt.c @@ -1,16 +1,88 @@ #include -#include +#include #include +#include -const uint16_t NUM_ID = 0; +#define NUM_ENTRIES 0 -void load_idt(struct InterruptDescriptorTable *idt) +struct InterruptDescriptor { + uint32_t offset; + uint32_t selector; + uint8_t gate_type; + uint8_t ring; + bool present; +}; + +struct IDT { + uint16_t size; + uint64_t* base; +} __attribute__((packed)); + +static uint64_t entries[NUM_ENTRIES]; +static size_t current_entry = 0; +struct IDT idt; + +static void encodeIdtEntry(uint8_t *target, struct InterruptDescriptor source) { - asm("lidt %0" : : "m"(idt)); + // Encode the present bit + if (source.present) { + target[5] |= 0xF0; + } else { + // Not present, return + return; + } + + // Encode the offset + target[0] = (source.offset >> 0x00) & 0xFF; + target[1] = (source.offset >> 0x08) & 0xFF; + target[6] = (source.offset >> 0x10) & 0xFF; + target[7] = (source.offset >> 0x18) & 0xFF; + + // Encode the base + target[2] = (source.selector >> 0x00) & 0xFF; + target[3] = (source.selector >> 0x08) & 0xFF; + + // Encode the gate type + target[5] |= source.gate_type; + + // Encode the DPL + target[5] |= (source.ring >> 5); + + print_hex_bytes(target, 8); } -void interrupt_initialize(struct InterruptDescriptorTable IDT) +static void add_entry(struct InterruptDescriptor entry) { - terminal_writestring("Loading IDT\n"); - load_idt(&IDT); + if (current_entry == NUM_ENTRIES) { + terminal_writestring("WARNING: More IDT entries than NUM_ENTRIES.\n"); + return; + } + + uint64_t descriptor = 0; + encodeIdtEntry((uint8_t*) &descriptor, entry); + + entries[current_entry] = descriptor; + + current_entry++; +} + +static void load_idt() +{ + idt.size = NUM_ENTRIES * 8 - 1; + idt.base = entries; + + for (int i = 0; i < NUM_ENTRIES; i++) { + print_hex_bytes(idt.base + i, 8); + terminal_putchar('\n'); + } + + asm ( "lidt %0" : : "m"(idt) ); +} + +void idt_init() +{ + terminal_writestring("TODO: Add interrupts"); + terminal_putchar('\n'); + + // load_idt(); } diff --git a/arch/i686/linker.ld b/arch/i686/linker.ld index f00fa2d..67bb60d 100644 --- a/arch/i686/linker.ld +++ b/arch/i686/linker.ld @@ -22,14 +22,14 @@ SECTIONS /* First put the multiboot header, as it is required to be put very early in the image or the bootloader won't recognize the file format. Next we'll put the .text section. */ - .text BLOCK(4K) : ALIGN(4K) + .text BLOCK (4K) : ALIGN(4K) { *(.multiboot) *(.text) } /* Read-only data. */ - .rodata BLOCK(4K) : ALIGN(4K) + .rodata BLOCK(4K) : ALIGN(4M) { *(.rodata) } diff --git a/arch/i686/tty.c b/arch/i686/tty.c index 346e3d6..7ee69c0 100644 --- a/arch/i686/tty.c +++ b/arch/i686/tty.c @@ -3,12 +3,6 @@ #include #include -/* Check if the compiler thinks you are targeting the wrong operating system. */ -#if defined(__linux__) -#error "You are not using a cross-compiler, you will most certainly run into trouble" -#endif - -/* This tutorial will only work for the 32-bit ix86 targets. */ #if !defined(__i386__) #error "This tutorial needs to be compiled with a ix86-elf compiler" #endif diff --git a/include/debugging.h b/include/debugging.h new file mode 100644 index 0000000..4fd0bf0 --- /dev/null +++ b/include/debugging.h @@ -0,0 +1,8 @@ +#include +#include +#include + +char get_last_key_pressed(); +void print_hex_digit(uint8_t digit); +void print_hex_byte(uint8_t byte); +void print_hex_bytes(void* bytes, size_t len); diff --git a/include/kernel/interrupt.h b/include/kernel/interrupt.h index 1d94c45..f6a293b 100644 --- a/include/kernel/interrupt.h +++ b/include/kernel/interrupt.h @@ -1,14 +1,4 @@ #include +#include -struct InterruptDescriptor -{ - -}; - -struct InterruptDescriptorTable -{ - uint16_t limit; /* Size of IDT array - 1 */ - struct InterruptDescriptor* base; /* Pointer to IDT array */ -} __attribute__((packed)); - -void interrupt_initialize(struct InterruptDescriptorTable IDT); +void idt_init(); diff --git a/isodir/boot/grub/grub.cfg b/isodir/boot/grub/grub.cfg index b2f8404..561f446 100644 --- a/isodir/boot/grub/grub.cfg +++ b/isodir/boot/grub/grub.cfg @@ -1,3 +1,3 @@ menuentry "myos" { - multiboot /boot/myos.bin + multiboot /boot/myos.kernel } diff --git a/isodir/boot/myos.bin b/isodir/boot/myos.bin deleted file mode 100755 index f8fdc9afa35baae6490b7fc857052ca2445e4209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10400 zcmeHNeQaA-6+cd#)=5|FrUhkR+A9iMCMq{hThWe0YL@0}&DWMWVPuKpBu-=1iH&`o zG@ywTGt?*RX%-TK3DjnwfzULm5>-fHY8(s;5dvCm5*ia##aiN!s3cHeZCK6kT)$^~ z6G+=XNJ#HS=iK`{=iGD8IrrWt`6^#-Y-_SuEM&AIDket%C{pMk`ooW8H3vzdBC4WN zvPnHTSguH#FDGIuVG-mxZwmBGXv$HdZ9I_kcwjcO0%irw3YZlzD_~Z@tbkbovjS!X z%nFzlFe_kI;D1$tqVuobUyQ}JI-j~enix&Q(vI5iPgU6Gl9|fq$)S*T;bD&D^%DLi zZ<)`arL;*M)7s7X{m`c7os#d9yj}7R$sd>evy!(-eq8b=ByW+tLGsT@{&~q;C3j2y zjO0&C{*>g+k~c|yO!98Y>m|2IUM6|JJu}wZwyF>J$YU!We&1CGClCkxBy3#=_QS9fA z<(z{_iY50$1;eiNlQ}K?!WX-7z|8~Dt_rx}^z+{v(_E12lzuZS)O_#u4fLm8a|}Wj!dbp^YwbNg_r{<5 zC01!?j>2BO(QBWp+XLKlX%M!HE4FUe+p*s&sH=9GCAcqJ72?zOA3I{nqER(50NIhn z=$~UL%jv~gBy{>F^R+8_`dCGMt(xpa@1OF^=*m*b16Zg6)_qGQ6&P|G@bnuA>mIUZ ztozCA%nr(%zFxwCZeJ?l_z9})K51X!IE_u1q>IXS-aG``a`(vP=!TYTM*I*j zKdM@Lv<6FTt5ev&$7WpfY&`jZV~ZA5`i|YcH+mHot24aM1yWI-x0W7o57K=wT3gB0 z6Y=))fvSr4+q%=2kPA+VcCc8DUVlCrtyr7XEoB(-#_QObBPlUxpDWHLhK!!oH#vSt z&xq4mv046F`fj{VPp4OFvc&FoM(6Vp6-F9;Ih}ehlQH~9XEoogKHj`Up;ci%t9e$;mvFn1*a5d~<}niY$op%VsV$=DKT$xWZ|slOa!%{IHgo$v`{O^$osjqG z7ql+rKj~e|s2CRL>E+2j@j67(cvzBS01?`lg{%vLpYb>3ymLU_&i2kNe zy9^&MJ#cKja_kkp!wzh{)@V~3Z^7gi_IWvl{WhCf z0kZ;T1*0h|C%Y*X;RIYi~Kf06Zw2kvPXX1t7^f3h3+0&ulOp|7E5`(^Y=t3pdUzKZ@R z{P8Os>(|gUQYj&Gw^VE;`Wm%(wUDDUqRzz*oS&OE;g_&o9%&~YvBhK0WqS^aU~ zBrv}uvV9*g|Nqg)bUXyiKh3ScoKG0|JNQA!d$tRF8kp;C=vClZ#Q%^!|19tZ;y3bn z1^9eHJ{N%#z`Vh{eiE1;Jq&*|6by=p2zx`$Al0|EHg`~aV|!~yQztdG)i-xjdwp|j z12wcXHXQGEw^KxThfjKjfz~LgBR-K`GZ(yn!Y};Zfd7j=3SkZ58S|a;3{8tdIO0Fy7lcKTe%==xMaL(o!`<#_ zJ(d>_MMp<{;d~L0c5a1S$a?(QWMsHpJzqhj;ouaJGcr9cyhG?kINOgIBjGzG$Qcff zc!k&K+05m1k#i^#A?I*#eB3u7a8N#E<1>Zhl>Of~QuyN2!nT6Rz})tN*iL?j@a)c} zXC;7;n{M|ghHS^5IeyqY`$?kvFg6> 4; int lower = byte & 0x0F; print_hex_digit(upper); print_hex_digit(lower); } + +void print_hex_bytes(void* bytes, size_t len) +{ + uint8_t* value = bytes; + for (size_t i = len; i > 0; i--) { + print_hex_byte(value[i - 1]); + } +} diff --git a/kernel/kernel.c b/kernel/kernel.c index d934a07..b67d528 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,12 +1,20 @@ #include #include -#include +#include + +/* Check if the compiler thinks you are targeting the wrong operating system. */ +#if defined(__linux__) +#error "You are not using a cross-compiler, you will most certainly run into trouble" +#endif void kernel_main(void) { /* Initialize terminal interface */ terminal_initialize(); + // TODO: Add interrupts + // idt_init(); + terminal_putchar(get_last_key_pressed()); char current_character = get_last_key_pressed(); @@ -17,11 +25,4 @@ void kernel_main(void) } current_character = tmp; } - - struct InterruptDescriptorTable IDTR = { - - }; - interrupt_initialize(IDTR); - - terminal_writestring("Hello World!"); }