Skip to content

Commit

Permalink
Merge pull request #4 from iomonad/gdt-implementation
Browse files Browse the repository at this point in the history
GDT Kernel Implementation
  • Loading branch information
iomonad authored Oct 2, 2020
2 parents 25a5780 + d9b0119 commit b144427
Show file tree
Hide file tree
Showing 15 changed files with 292 additions and 86 deletions.
17 changes: 10 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#
# (c) 2020 iomonad <iomonad@riseup.net>
#
Expand All @@ -16,16 +15,19 @@ TARGET_ISO = kfs.iso
prepare:
mkdir -p $(BUILD_DIR)

bootloader: prepare
$(ASM) $(ASM_FLAGS) $(ASM_SRC) -o $(BOOTLOADER_TARGET)
bootloader: prepare $(ASM_TARGETS)
boot/%.o: boot/%.asm
printf "ASM\t\t%s\n" $<
$(ASM) $(ASM_FLAGS) $< -o $@

kernel: $(KERNEL_TARGETS)

$(KERNEL_SRC_DIR)/%.o: $(KERNEL_SOURCES)/%.c
kernel/sources/%.o: kernel/sources/%.c
printf "CC\t\t%s\n" $<
$(CC) $(CFLAGS) -c $< -o $@

rom: bootloader kernel
$(LINKER) $(LFLAGS) $(BOOTLOADER_TARGET) $(KERNEL_TARGETS) -o $(TARGET)
printf "\nLD\t\t%s\n" $(TARGET)
$(LINKER) $(LFLAGS) $(ASM_TARGETS) $(KERNEL_TARGETS) -o $(TARGET)

post:
strip $(TARGET)
Expand All @@ -38,7 +40,7 @@ iso: rom post

clean:
rm -fr $(BUILD_DIR) isodir
rm -f $(KERNEL_TARGETS)
rm -fr $(KERNEL_TARGETS) $(ASM_TARGETS)

fclean: clean
rm -f $(TARGET) *.iso
Expand All @@ -49,3 +51,4 @@ re: fclean rom

.PHONY: prepare bootloader kernel rom post clean fclean
.DEFAULT_GOAL := rom
MAKEFLAGS += --silent --no-builtin-rules
62 changes: 62 additions & 0 deletions boot/gdt.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
;;
;; (c) 2020 iomonad <clement@trosa.io>
;; This is part of the KFS Project
;; See: https://github.com/iomonad/KFS
;;

bits 32

;; Global Descriptor Table Implementation
;; See:
;; - https://wiki.osdev.org/Global_descriptor_table
;;
;; A vital part of the 386's various protection
;; measures is the GDT. It defines base accecss privilege
;; for certain parts of memory.
;; --
;; One of the key use is to generate violation exceptions
;; that give kernel a way to end process that
;; doing unauthorized memory access.
;; --
;; An important thing to know is that GRUB AUTOMATICALLY install
;; GDT when create rescue disk or installed on device.
;; If grub memory area is overrided, the GDT is trashed up
;; and will cause a 'Triple-Fault' (Basically will reset machine)
;; To prevent that, we should implement our own GDT in a place that
;; we know and have possibility to access.
;; --
;; * In short terms, to build our GDT, we should:
;; - Tell processor were it is located
;; - Load [CS-DS-ES-FS-GS] Registers to our entry.
;; * Behaviour to keep in mind:
;; - The Code Segment (CS) tell processor which offset into
;; the GDT that it will find the access privileges in which to
;; execute the current code.
;; - The Data Segment (DS) have the same idea but not for code,
;; it's the Data segment and defines the access privileges for.
;; the current data.
;; - [ES,FS,GS] are used as alternate DS registers.
;; * GDT Architecture
;; - It's a list of 64-bits long entries.
;; - These entries define where in memory that the allowed region
;; will start, as well as the limit of this region, and the
;; access privileges associated with this entry.
;; - It's important to have the first entry of our GDT set as NULL,
;; also known as the `NULL Descriptor`.
;; - Also, no segments regisers should be set to 0, otherwise it
;; will raise a General Protection fault, an protection
;; feature of the processor.
global _gdt_commit
extern _gdtptr ; GDT Pointer globally defined

_gdt_commit:
lgdt [_gdtptr] ; Load GDT to our global ptr
mov ax, 0x10 ; Data segment offset from our GDT
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:_kflush ; Code segment offset jump
_kflush:
ret ; Leave state and return to C implementation
51 changes: 51 additions & 0 deletions kernel/includes/gdt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
*
* (c) 2020 iomonad <clement@trosa.io>
*
* This is part of the KFS Project
* See: https://github.com/iomonad/KFS
*
*/
#ifndef GDT_H
#define GDT_H

#include <types.h>
#include <kernel.h>

#define GDT_SIZE 3

/*
* Modelize an GDT entry
*/
struct _kgdt_entry {
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__ ((packed));

/*
* Modelize a pointer that implement
* an limit wich basically is the max
* bytes taken up by the GDT-1.
*/
struct _kgdt_ptr {
uint16_t limit;
uint32_t base;
} __attribute__ ((packed));

/*
* Flush function that reload
* our Segment registers.
*/
extern void _gdt_commit(void);

/* Prototypes */

void install_system_gdt(void);;
void kgdt_add_entry(uint8_t index, uint64_t base, uint64_t limit,
uint8_t access, uint8_t granularity);

#endif /* GDT_H */
1 change: 0 additions & 1 deletion kernel/includes/keyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,5 @@ extern __k_equivalence __ascii_key_table[];
/* PROTOTYPES */

char kgetkey(void);
void input_vga_showcase(void);

#endif /* KEYBOARD_H */
1 change: 1 addition & 0 deletions kernel/includes/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long uint64_t;

#endif /* TYPES_H */
74 changes: 74 additions & 0 deletions kernel/sources/gdt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
*
* (c) 2020 iomonad <clement@trosa.io>
*
* This is part of the KFS Project
* See: https://github.com/iomonad/KFS
*
*/
#include <gdt.h>
#include <kernel.h>

/* Global In memory GDT datastructure */
struct _kgdt_entry gdt[GDT_SIZE];
struct _kgdt_ptr _gdtptr;

/*
* Add new descriptor to the table wo/ flush
*/
void kgdt_add_entry(uint8_t index, uint64_t base, uint64_t limit,
uint8_t access, uint8_t granularity)
{
/* BASE ADDR SETUP */
gdt[index].base_low = (base & 0xFFFF);
gdt[index].base_middle = (base >> 16) & 0xFF;
gdt[index].base_high = (base >> 24) & 0xFF;

/* LIMIT SETUP */
gdt[index].limit_low = (limit & 0xFFFF);
gdt[index].granularity = ((limit >> 16) & 0x0F);

/* GRANULARITY & ACCESS */
gdt[index].granularity |= (granularity & 0xF0);
gdt[index].access = access;
}

/*
* GDT Setup
*/
void install_system_gdt(void)
{
/*
* Initialize convenient structure
*/
_gdtptr.limit = (sizeof(struct _kgdt_entry) * GDT_SIZE) - 1;
_gdtptr.base = (uint32_t)&gdt;

/* Stick to standard guideline */
kgdt_add_entry(0x00, 0, 0, 0, 0);

/*
* Code Segment:
* -------------
* Parameters:
* -> Slot: 1
* -> Base Address: 0
* -> Segment Limit: 4GB
* -> Access: 0x9A (for code)
* -> Granularity: 4kb
*/
kgdt_add_entry(0x01, 0, 0xFFFFFFFF, 0x9A, 0xCF);

/*
* Data Segment:
* -------------
* -> Slot: 1
* -> Base Address: 0
* -> Segment Limit: 4GB
* -> Access: 0x92 (for data)
* -> Granularity: 4kb
*/
kgdt_add_entry(0x02, 0, 0xFFFFFFFF, 0x92, 0xCF);

_gdt_commit();
}
24 changes: 19 additions & 5 deletions kernel/sources/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* See: https://github.com/iomonad/KFS
*
*/
#include <gdt.h>
#include <vga.h>
#include <time.h>
#include <kernel.h>
Expand All @@ -21,12 +22,25 @@ uint16_t vga_buffer_line_pos = 0x01;
/* Need to auto determine in future */
__supported_platform __running_platform = QEMU;

void __kmain()
static void __attribute__ ((cold))
__kernel_init_hook(void)
{
/* Setup VGA */
vga_clear_screen();
vga_puts("42");
vga_endl();
vga_puts("System is going to halt !");
ksleep(4000000000);

/*
* Install GDT
*/
install_system_gdt();
vga_puts("GDT Installed!");
}

void __kmain()
{
/* Prepare kernel datastructures */
__kernel_init_hook();
for (;;) {
asm volatile ("nop");
}
return kshutdown();
}
55 changes: 21 additions & 34 deletions kernel/sources/keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,28 +76,11 @@ output_kb(uint16_t kb_port, uint8_t data)
asm volatile("outb %0, %1" : "=a"(data) : "d"(kb_port));
}

/*
* Get key input frow keyport
* hardware port
*/
char kgetkey(void)
{
char c = 0;

while ((c = input_kb(KEYBOARD_PORT)) != 0) {
if (likely(c >= 0)) {
goto _valid;
}
}
_valid:
return c;
}

/*
* Convert input key to ascii
* equivalent
*/
char keytoascii(const char key)
static char keytoascii(const char key)
{
uint32_t tsize;

Expand All @@ -110,23 +93,27 @@ char keytoascii(const char key)
return 0x00;
}

/*
* Get key input frow keyport
* hardware port
*/
char kgetkey(void)
{
char c = 0;

void input_vga_showcase(void) {

char ch = 0;
char keycode = 0;

do {
keycode = kgetkey();
if(keycode == KEY_ENTER) {
vga_endl();
} else if (keycode == KEY_BACKSPACE) {
vga_delchar();
} else {
ch = keytoascii(keycode);
vga_putchar(ch);
while ((c = input_kb(KEYBOARD_PORT)) != 0) {
if (likely(c >= 0)) {
goto _valid;
}
ksleep(KERNEL_STD_DELAY);
} while(ch >= 0);
}
_valid:
return c;
}

/*
* Same implementation for `kgetkey` but
* return associated char for QWERTY Layout
*/
char kgetchar(void) {
return keytoascii(kgetkey());
}
30 changes: 30 additions & 0 deletions kfs.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* entry point of our kernel */
ENTRY(kfs_entry)

SECTIONS
{
/* we need 1MB of space atleast */
. = 1M;

/* text section */
.text BLOCK(4K) : ALIGN(4K) {
*(.multiboot)
*(.text)
}

/* read only data section */
.rodata BLOCK(4K) : ALIGN(4K) {
*(.rodata)
}

/* data section */
.data BLOCK(4K) : ALIGN(4K) {
*(.data)
}

/* bss section */
.bss BLOCK(4K) : ALIGN(4K) {
*(COMMON)
*(.bss)
}
}
Loading

0 comments on commit b144427

Please sign in to comment.