Compare commits
3 Commits
013b5a557e
...
ecc91fdc7d
Author | SHA1 | Date | |
---|---|---|---|
ecc91fdc7d | |||
89c02d6a93 | |||
c50d3f14a6 |
@ -1,3 +1,7 @@
|
|||||||
|
; Here is our entry point to the kernel
|
||||||
|
; A very simple assembly file
|
||||||
|
; We set up some parameters and then pass the execution to our kmain
|
||||||
|
|
||||||
global loader ; entry symbol for ELF
|
global loader ; entry symbol for ELF
|
||||||
extern kmain
|
extern kmain
|
||||||
|
|
||||||
@ -6,12 +10,17 @@ FLAGS equ 0x3
|
|||||||
CHECKSUM equ -(MAGIC_NUMBER + FLAGS) ; calculate the checksum
|
CHECKSUM equ -(MAGIC_NUMBER + FLAGS) ; calculate the checksum
|
||||||
KERNEL_STACK_SIZE equ 4096
|
KERNEL_STACK_SIZE equ 4096
|
||||||
|
|
||||||
|
; The multiboot section is a semi requirement for grub
|
||||||
|
; All this is doing is placing the required magic number, flags, and the checksum into the file first
|
||||||
|
; This lets grub know if this is a valid multiboot kernel or not
|
||||||
section .multiboot
|
section .multiboot
|
||||||
align 4 ; code must be 4 byte aligned
|
align 4 ; code must be 4 byte aligned
|
||||||
dd MAGIC_NUMBER
|
dd MAGIC_NUMBER
|
||||||
dd FLAGS
|
dd FLAGS
|
||||||
dd CHECKSUM
|
dd CHECKSUM
|
||||||
|
|
||||||
|
; Here we're setting up the stack
|
||||||
|
; Giving us 4096 bytes (resb)
|
||||||
section .bss
|
section .bss
|
||||||
align 4
|
align 4
|
||||||
kernel_stack:
|
kernel_stack:
|
||||||
@ -19,10 +28,12 @@ kernel_stack:
|
|||||||
|
|
||||||
section .text
|
section .text
|
||||||
loader:
|
loader:
|
||||||
mov esp, kernel_stack + KERNEL_STACK_SIZE
|
mov esp, kernel_stack + KERNEL_STACK_SIZE ; move the top of the stack into esp
|
||||||
|
|
||||||
call kmain
|
call kmain ; pass execution over to our kmain function, where all of the real stuff is done
|
||||||
|
|
||||||
;cli
|
; Should the system exit, we clear the interrupt flag
|
||||||
|
; and do an infinite loop of nothing
|
||||||
|
cli
|
||||||
loop: hlt
|
loop: hlt
|
||||||
jmp loop
|
jmp loop
|
||||||
|
@ -6,6 +6,25 @@
|
|||||||
#include <kernel/_kernel.h>
|
#include <kernel/_kernel.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What is this file?
|
||||||
|
*
|
||||||
|
* Well, to properly set up a lot of the system, we need something called a GDT
|
||||||
|
* or, a Global Descriptor Table.
|
||||||
|
*
|
||||||
|
* This table, establishes a few things.
|
||||||
|
*
|
||||||
|
* Mainly it sets 4 segments,
|
||||||
|
* A kernel code segment, with RING 0 permissions
|
||||||
|
* A kernel data segment, with RING 0 permissions
|
||||||
|
* A user code segment, with RING 3 permissions
|
||||||
|
* A user data segment, with RING 3 permissions
|
||||||
|
*
|
||||||
|
* This allows for future userspace to properly segment code and data,
|
||||||
|
* anything in userspace shouldn't have access to hardware like the kernel does
|
||||||
|
* So by passing through this GDT, we can dish out authority to access certain data, functions,
|
||||||
|
* etc, by going through the CPU permission system (RING 0 - 3)
|
||||||
|
*/
|
||||||
|
|
||||||
uint64_t gdt[GDT_SIZE];
|
uint64_t gdt[GDT_SIZE];
|
||||||
|
|
||||||
@ -26,12 +45,14 @@ uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
|
|||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __TESTING__
|
||||||
void dump_gdt(void)
|
void dump_gdt(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < GDT_SIZE; i++) {
|
for (int i = 0; i < GDT_SIZE; i++) {
|
||||||
printf("GDT_ENTRY %d: %4 | %2\n", i, gdt[i], gdt[i]);
|
printf("GDT_ENTRY %d: %4 | %2\n", i, gdt[i], gdt[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void gdt_init(void)
|
void gdt_init(void)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <kernel/x86/idt.h>
|
#include <kernel/x86/idt.h>
|
||||||
#include <kernel/x86/pic.h>
|
#include <kernel/x86/pic.h>
|
||||||
|
#include <kernel/x86/io.h>
|
||||||
|
|
||||||
__attribute__((aligned(0x10)))
|
__attribute__((aligned(0x10)))
|
||||||
static idt_entry_t idt[256];
|
static idt_entry_t idt[256];
|
||||||
@ -20,7 +21,13 @@ void exception_handler(unsigned int i)
|
|||||||
kerror("EXCEPTION");
|
kerror("EXCEPTION");
|
||||||
printf("Exeption: %u\n", i);
|
printf("Exeption: %u\n", i);
|
||||||
#endif
|
#endif
|
||||||
__asm__ volatile ("cli; hlt"); // hangs the computer
|
if (i <= 31)
|
||||||
|
__asm__ volatile ("cli; hlt"); // hangs the computer
|
||||||
|
|
||||||
|
if (i == PIC_PIT) {
|
||||||
|
printf("Sending EOI instruction to PIT\n");
|
||||||
|
PIC_sendEOI(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void idt_set_descriptor(uint8_t vector, void *isr, uint8_t flags)
|
void idt_set_descriptor(uint8_t vector, void *isr, uint8_t flags)
|
||||||
@ -52,7 +59,8 @@ void idt_init(void)
|
|||||||
__asm__ volatile("lidt %0" : : "m"(idtr)); // load the new IDT
|
__asm__ volatile("lidt %0" : : "m"(idtr)); // load the new IDT
|
||||||
|
|
||||||
PIC_remap(0x20, 0x28);
|
PIC_remap(0x20, 0x28);
|
||||||
IRQ_set_mask(0xfd); // unmask IRQ1
|
pic_disable(); // mask everything
|
||||||
|
IRQ_clear_mask(1);
|
||||||
|
|
||||||
__asm__ volatile("sti"); // set the interrupt flag
|
__asm__ volatile("sti"); // set the interrupt flag
|
||||||
#ifdef __TESTING__
|
#ifdef __TESTING__
|
||||||
|
@ -3,6 +3,7 @@ extern exception_handler
|
|||||||
%macro isr_err_stub 1
|
%macro isr_err_stub 1
|
||||||
isr_stub_%+%1:
|
isr_stub_%+%1:
|
||||||
pushad
|
pushad
|
||||||
|
cld
|
||||||
push dword %1
|
push dword %1
|
||||||
call exception_handler
|
call exception_handler
|
||||||
popad
|
popad
|
||||||
@ -12,6 +13,7 @@ isr_stub_%+%1:
|
|||||||
%macro isr_no_err_stub 1
|
%macro isr_no_err_stub 1
|
||||||
isr_stub_%+%1:
|
isr_stub_%+%1:
|
||||||
pushad
|
pushad
|
||||||
|
cld
|
||||||
push dword %1
|
push dword %1
|
||||||
call exception_handler
|
call exception_handler
|
||||||
popad
|
popad
|
||||||
|
@ -1,25 +1,41 @@
|
|||||||
ENTRY(loader)
|
/**
|
||||||
|
* This is the linker file.
|
||||||
|
*
|
||||||
|
* This file tells the linker (ld) how we want to arrange the code into the output file.
|
||||||
|
*/
|
||||||
|
ENTRY(loader) /* This is the first entry point, defined in boot.s */
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 1M;
|
/*
|
||||||
|
* This is telling the linker that anything after here should be loaded at 2M onwards
|
||||||
|
* The reason for 2M, is that we want to give room for the BIOS, (and UEFI), 2M is generally regarded as a safe spot
|
||||||
|
* to place the memory offset
|
||||||
|
* */
|
||||||
|
. = 2M;
|
||||||
|
|
||||||
.text BLOCK(4K) : ALIGN(4K)
|
/*
|
||||||
|
* BLOCK is an alias for ALIGN, we're telling the linker that we want each section to be aligned at 4K
|
||||||
|
*/
|
||||||
|
.text BLOCK(4K) : ALIGN(4K) /* The first section we want is the text section, this is where most code is */
|
||||||
{
|
{
|
||||||
*(.multiboot)
|
*(.multiboot) /* Multiboot needs to be early in the file, required by grub */
|
||||||
*(.text)
|
*(.text) /* The text section */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* R/O data */
|
||||||
.rodata BLOCK(4K) : ALIGN(4K)
|
.rodata BLOCK(4K) : ALIGN(4K)
|
||||||
{
|
{
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Data */
|
||||||
.data BLOCK(4K) : ALIGN(4K)
|
.data BLOCK(4K) : ALIGN(4K)
|
||||||
{
|
{
|
||||||
*(.data)
|
*(.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BSS */
|
||||||
.bss BLOCK(4K) : ALIGN(4K)
|
.bss BLOCK(4K) : ALIGN(4K)
|
||||||
{
|
{
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#ifdef __TESTING__
|
#ifdef __TESTING__
|
||||||
#include <kernel/_kernel.h>
|
#include <kernel/_kernel.h>
|
||||||
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
#include <kernel/x86/io.h>
|
#include <kernel/x86/io.h>
|
||||||
#include <kernel/x86/pic.h>
|
#include <kernel/x86/pic.h>
|
||||||
@ -71,6 +72,8 @@ void IRQ_set_mask(uint8_t IRQline) // Masked IRQlines are ignored by the PIC, ma
|
|||||||
IRQline -= 8;
|
IRQline -= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("%x %x\n", port, IRQline);
|
||||||
|
|
||||||
value = inb(port) | (1 << IRQline);
|
value = inb(port) | (1 << IRQline);
|
||||||
outb(port, value);
|
outb(port, value);
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,23 @@
|
|||||||
#define PIC_READ_ISR 0x0b /** OCW3 irq service next CMD read **/
|
#define PIC_READ_ISR 0x0b /** OCW3 irq service next CMD read **/
|
||||||
|
|
||||||
|
|
||||||
|
#define PIC_PIT 32
|
||||||
|
#define PIC_KEYB 33
|
||||||
|
#define PIC_CASCADE 34 // never raised
|
||||||
|
#define PIC_COM2 35
|
||||||
|
#define PIC_COM1 36
|
||||||
|
#define PIC_LPT2 37
|
||||||
|
#define PIC_FLOPPY_DISK 38
|
||||||
|
#define PIC_LPT1 39 // usually spurious interrupt
|
||||||
|
#define PIC_CMOS 40
|
||||||
|
#define PIC_FREE_ONE 41
|
||||||
|
#define PIC_FREE_TWO 42
|
||||||
|
#define PIC_FREE_THREE 43
|
||||||
|
#define PIC_PS2_MOUSE 44
|
||||||
|
#define PIC_FPU 45
|
||||||
|
#define PIC_ATA_ONE 46
|
||||||
|
#define PIC_ATA_TWO 47
|
||||||
|
|
||||||
void PIC_sendEOI(uint8_t irq);
|
void PIC_sendEOI(uint8_t irq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,4 +22,23 @@ void kmain(void)
|
|||||||
serial_initialize();
|
serial_initialize();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The computer is now hanging on INTERRUPT 32,
|
||||||
|
* this is good because that means the PIC is working, its the timer interrupt, except... the PIT is masked off...
|
||||||
|
* we need to now implement the ISR routines in exception_handler,
|
||||||
|
* first i want to implement all of the code for the basic exceptions..
|
||||||
|
* then i want to setup the PIC triggers
|
||||||
|
*
|
||||||
|
* now for keyboard stuff, i believe i need to start looking into setting up a ps/2 driver before the interrupts will even start arriving..
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
printf("Entering loop...\n");
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf("Exiting loop...\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user