-
Notifications
You must be signed in to change notification settings - Fork 90
Various bug fixes as well as a change to provide our own GDT. #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
d4c0a6c
234f40a
642fe51
deb6b7a
7b99635
87e796e
d2b959a
ea847eb
63c1629
9d4c881
cade471
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| *.o | ||
| kernel | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
|
|
||
| CFLAGS += -ffreestanding | ||
|
|
||
| SRCS := head.asm kernel.c | ||
| OBJS := $(foreach src,$(SRCS),$(basename $(src)).o) | ||
|
|
||
| LINK_SCRIPT := link.ld | ||
|
|
||
| KERN_BIN := kernel | ||
|
|
||
| all: $(KERN_BIN) | ||
|
|
||
| clean: | ||
| rm $(KERN_BIN) | ||
| rm $(OBJS) | ||
|
|
||
| $(KERN_BIN): $(OBJS) | ||
| ld -m elf_i386 -T $(LINK_SCRIPT) -o $@ $(OBJS) | ||
|
|
||
| # Rule for compiling nasm assembly | ||
| %.o: %.asm | ||
| nasm -f elf32 $< -o $@ | ||
|
|
||
| # Rule for compiling C | ||
| %.o: %.c | ||
| gcc -m32 $(CFLAGS) -c $< -o $@ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,6 @@ | |
| * Copyright (C) 2014 Arjun Sreedharan | ||
| * License: GPL version 2 or higher http://www.gnu.org/licenses/gpl.html | ||
| */ | ||
| #include <stdio.h> | ||
| #include "keyboard_map.h" | ||
|
|
||
| /* there are 25 lines each of 80 columns; each element takes 2 bytes */ | ||
|
|
@@ -15,37 +14,130 @@ | |
| #define KEYBOARD_STATUS_PORT 0x64 | ||
| #define IDT_SIZE 256 | ||
| #define INTERRUPT_GATE 0x8e | ||
| #define KERNEL_CODE_SEGMENT_OFFSET 0x08 | ||
| #define KERNEL_CODE_SEGMENT_OFFSET KERNEL_CS | ||
|
|
||
| #define GDT_SIZE 3 | ||
| #define GDT_MEM_LOW 0 | ||
| #define GDT_MEM_LEN 0xFFFFFFFF | ||
|
|
||
| #define GDT_EXE 0x8 | ||
| #define GDT_READ 0x2 | ||
| #define GDT_WRITE 0x2 | ||
|
|
||
| /* Kernel code always runs in ring 0 */ | ||
| #define DPL_KERNEL 0 | ||
|
|
||
| /* GDT entry numbers */ | ||
| enum { | ||
| _GDT_NULL, | ||
| _KERNEL_CS, | ||
| _KERNEL_DS | ||
| }; | ||
|
|
||
| /* GDT entry offsets */ | ||
| #define GDT_NULL (_GDT_NULL << 3) | ||
| #define KERNEL_CS (_KERNEL_CS << 3) | ||
| #define KERNEL_DS (_KERNEL_DS << 3) | ||
|
|
||
| #define ENTER_KEY_CODE 0x1C | ||
|
|
||
| extern unsigned char keyboard_map[128]; | ||
| extern void keyboard_handler(void); | ||
| extern char read_port(unsigned short port); | ||
| extern void write_port(unsigned short port, unsigned char data); | ||
| extern void load_idt(unsigned long *idt_ptr); | ||
|
|
||
| /* current cursor location */ | ||
| unsigned int current_loc = 0; | ||
| /* video memory begins at address 0xb8000 */ | ||
| char *vidptr = (char*)0xb8000; | ||
|
|
||
| struct GDT_entry { | ||
| /* Low 8 bits of the "limit", or length of memory this descriptor refers to. */ | ||
| unsigned short limit_low; | ||
| unsigned short base_low; /* 'Low' 16-bits of the base */ | ||
| unsigned char base_middle; /* 'middle' 8 bits of the base */ | ||
|
|
||
| unsigned char type :4; /* Flags for type of memory this descriptor describes */ | ||
| unsigned char one :1; | ||
| unsigned char dpl :2; /* Descriptor privilege level - Ring level */ | ||
| unsigned char present :1; /* 1 for any valid GDT entry */ | ||
|
|
||
| unsigned char limit :4; /* Top 4 bytes of 'limit' */ | ||
| unsigned char avilable :1; | ||
| unsigned char zero :1; | ||
| unsigned char op_size :1; /* Selects between 16-bit and 32-bit */ | ||
| unsigned char gran :1; /* If this bit is set, then 'limit' is a count of 4K blocks, not bytes */ | ||
|
|
||
| unsigned char base_high; /* High 8 bits of the base */ | ||
| } __attribute__((packed)); | ||
|
|
||
| struct gdt_ptr { | ||
| unsigned short limit; | ||
| unsigned long base; | ||
| } __attribute__((packed)); | ||
|
|
||
| extern void load_gdt(struct gdt_ptr *gdt_ptr); | ||
|
|
||
| #define GDT_ENTRY(gdt_type, gdt_base, gdt_limit, gdt_dpl) \ | ||
| { \ | ||
| .limit_low = (((gdt_limit) >> 12) & 0xFFFF), \ | ||
| .base_low = ((gdt_base) & 0xFFFF), \ | ||
| .base_middle = (((gdt_base) >> 16) & 0xFF), \ | ||
| .type = gdt_type, \ | ||
| .one = 1, \ | ||
| .dpl = gdt_dpl, \ | ||
| .present = 1, \ | ||
| .limit = ((gdt_limit) >> 28), \ | ||
| .avilable = 0, \ | ||
| .zero = 0, \ | ||
| .op_size = 1, \ | ||
| .gran = 1, \ | ||
| .base_high = (((gdt_base) >> 24) & 0xFF), \ | ||
| } | ||
|
|
||
| /* Define our GDT that we'll use - We know everything upfront, so we just | ||
| * initalize it with the correct settings. | ||
| * | ||
| * This sets up the NULL, entry, and then the kernel's CS and DS segments, | ||
| * which just span all 4GB of memory. */ | ||
| struct GDT_entry GDT[GDT_SIZE] = { | ||
| [_GDT_NULL] = { 0 /* NULL GDT entry - Required */ }, | ||
| [_KERNEL_CS] = GDT_ENTRY(GDT_EXE | GDT_READ, 0, 0xFFFFFFFF, DPL_KERNEL), | ||
| [_KERNEL_DS] = GDT_ENTRY(GDT_WRITE, 0, 0xFFFFFFFF, DPL_KERNEL) | ||
| }; | ||
|
|
||
| void gdt_init(void) | ||
| { | ||
| struct gdt_ptr gdt_ptr; | ||
|
|
||
| gdt_ptr.base = (unsigned long)GDT; | ||
| gdt_ptr.limit = sizeof(GDT); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be |
||
| load_gdt(&gdt_ptr); | ||
| } | ||
|
|
||
|
|
||
| struct IDT_entry{ | ||
| unsigned short int offset_lowerbits; | ||
| unsigned short int selector; | ||
| unsigned char zero; | ||
| unsigned char type_attr; | ||
| unsigned short int offset_higherbits; | ||
| }; | ||
| } __attribute__((packed)); | ||
|
|
||
| struct idt_ptr { | ||
| unsigned short limit; | ||
| unsigned long base; | ||
| } __attribute__((packed)); | ||
|
|
||
| extern void load_idt(struct idt_ptr *idt_ptr); | ||
|
|
||
| struct IDT_entry IDT[IDT_SIZE]; | ||
|
|
||
|
|
||
| void idt_init(void) | ||
| { | ||
| unsigned long keyboard_address; | ||
| unsigned long idt_address; | ||
| unsigned long idt_ptr[2]; | ||
| struct idt_ptr idt_ptr; | ||
|
|
||
| /* populate IDT entry of keyboard's interrupt */ | ||
| keyboard_address = (unsigned long)keyboard_handler; | ||
|
|
@@ -87,11 +179,10 @@ void idt_init(void) | |
| write_port(0xA1 , 0xff); | ||
|
|
||
| /* fill the IDT descriptor */ | ||
| idt_address = (unsigned long)IDT ; | ||
| idt_ptr[0] = (sizeof (struct IDT_entry) * IDT_SIZE) + ((idt_address & 0xffff) << 16); | ||
| idt_ptr[1] = idt_address >> 16 ; | ||
| idt_ptr.limit = sizeof(IDT); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes I think you're right, but FWIW it shouldn't matter that much since nothing should read past the end of the IDT or GDT (and if they did, are likely to read more than one byte). |
||
| idt_ptr.base = (unsigned long)IDT; | ||
|
|
||
| load_idt(idt_ptr); | ||
| load_idt(&idt_ptr); | ||
| } | ||
|
|
||
| void kb_init(void) | ||
|
|
@@ -156,9 +247,11 @@ void kmain(void) | |
| kprint_newline(); | ||
| kprint_newline(); | ||
|
|
||
| gdt_init(); | ||
| idt_init(); | ||
| kb_init(); | ||
|
|
||
| while(1); | ||
| while(1) | ||
| asm volatile ("hlt"); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't be in reverse order?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say you would be right. I'm guessing I never noticed this bug because all of those segments probably contain the same value everywhere in the program. but obviously it's still a bug and it would easily blow things up if/when features are added that make use of the segment registers (Such as using them for CPU-local data).
On that note it also appears the segments are also never assigned, so it's quite likely this code got lucky in other areas. A while back I had an issue stemming from something similar in my kernel, it's fixed here. The code in this PR doesn't reload the segments after the
lgdt, but that's necessary to ensure they actually contain the correct values and also to ensure they start utilizing the newly defined segments.