Legacy OS files. Have an i686-elf-gcc & -ld in your PATH,
and the Makefile will take care of the rest.
This commit is contained in:
commit
f6ba6aa117
46
boot.s
Normal file
46
boot.s
Normal file
|
@ -0,0 +1,46 @@
|
|||
;
|
||||
; boot.s -- Kernel start location. Also defines multiboot header.
|
||||
; Based on Bran's kernel development tutorial file start.asm
|
||||
;
|
||||
|
||||
MBOOT_PAGE_ALIGN equ 1<<0 ; Load kernel and modules on a page boundary
|
||||
MBOOT_MEM_INFO equ 1<<1 ; Provide your kernel with memory info
|
||||
MBOOT_HEADER_MAGIC equ 0x1BADB002 ; Multiboot Magic value
|
||||
; NOTE: We do not use MBOOT_AOUT_KLUDGE. It means that GRUB does not
|
||||
; pass us a symbol table.
|
||||
MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
|
||||
MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)
|
||||
|
||||
|
||||
[BITS 32] ; All instructions should be 32-bit.
|
||||
|
||||
[GLOBAL mboot] ; Make 'mboot' accessible from C.
|
||||
[EXTERN code] ; Start of the '.text' section.
|
||||
[EXTERN bss] ; Start of the .bss section.
|
||||
[EXTERN end] ; End of the last loadable section.
|
||||
|
||||
mboot:
|
||||
dd MBOOT_HEADER_MAGIC ; GRUB will search for this value on each
|
||||
; 4-byte boundary in your kernel file
|
||||
dd MBOOT_HEADER_FLAGS ; How GRUB should load your file / settings
|
||||
dd MBOOT_CHECKSUM ; To ensure that the above values are correct
|
||||
|
||||
dd mboot ; Location of this descriptor
|
||||
dd code ; Start of kernel '.text' (code) section.
|
||||
dd bss ; End of kernel '.data' section.
|
||||
dd end ; End of kernel.
|
||||
dd start ; Kernel entry point (initial EIP).
|
||||
|
||||
[GLOBAL start] ; Kernel entry point.
|
||||
[EXTERN kernel_main] ; This is the entry point of our C code
|
||||
|
||||
start:
|
||||
; Load multiboot information:
|
||||
push ebx
|
||||
|
||||
; Execute the kernel:
|
||||
cli ; Disable interrupts.
|
||||
call kernel_main ; call our main() function.
|
||||
jmp $ ; Enter an infinite loop, to stop the processor
|
||||
; executing whatever rubbish is in the memory
|
||||
; after our kernel!
|
72
common.c
Normal file
72
common.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "headers/common.h"
|
||||
#include "headers/screen.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void memcpy(void *dest, void *src, unsigned int n)
|
||||
{
|
||||
// Typecast src and dest addresses to (char *)
|
||||
char *csrc = (char *)src;
|
||||
char *cdest = (char *)dest;
|
||||
|
||||
// Copy contents of src[] to dest[]
|
||||
for (unsigned int i=0; i<n; i++)
|
||||
cdest[i] = csrc[i];
|
||||
}
|
||||
|
||||
void memset(void *s, int c, unsigned int n)
|
||||
{
|
||||
unsigned char* p=s;
|
||||
while(n--)
|
||||
*p++ = (unsigned char)c;
|
||||
}
|
||||
|
||||
|
||||
unsigned char inb(unsigned short port) {
|
||||
/* a handy c wrapper funciton that reads a byte from the specificed port
|
||||
"=a" (result) means: put al register in variable RESULT when finished
|
||||
"d" (port) means: load EDX with port */
|
||||
unsigned char result;
|
||||
__asm__("in al, dx" : "=a" (result) : "d" (port));
|
||||
return result;
|
||||
}
|
||||
|
||||
void outb(unsigned short port, unsigned char data) {
|
||||
// "a" (data) means: load EAX with data
|
||||
// "d" (port) means: load EDX with port
|
||||
__asm__("out dx, al" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
unsigned short inw(unsigned short port) {
|
||||
unsigned short result;
|
||||
__asm__("in ax, dx" : "=a" (result) : "d" (port));
|
||||
return result;
|
||||
}
|
||||
|
||||
void outw(unsigned short port, unsigned short data) {
|
||||
__asm__("out dx, ax" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
void panic(const char *message, const char *file, uint32_t line) {
|
||||
// We encountered a massive problem and have to stop.
|
||||
asm volatile("cli"); // Disable interrupts.
|
||||
|
||||
//Print stack trace
|
||||
kprintf("PANIC(%s) at %s : %d\n",message,file,line);
|
||||
//Halt
|
||||
for(;;);
|
||||
}
|
||||
|
||||
void panic_assert(const char *file, uint32_t line, const char *desc) {
|
||||
// An assertion failed, and we have to panic.
|
||||
asm volatile("cli"); // Disable interrupts.
|
||||
|
||||
kprintf("ASSERTION-FAILED(%s) at %s : %d\n",desc,file,line);
|
||||
// Halt by going into an infinite loop.
|
||||
for(;;);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
161
descriptor_tables.c
Normal file
161
descriptor_tables.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// descriptor_tables.c - Initialises the GDT and IDT, and defines the
|
||||
// default ISR and IRQ handler.
|
||||
// Based on code from Bran's kernel development tutorials.
|
||||
// Rewritten for JamesM's kernel development tutorials.
|
||||
//
|
||||
|
||||
#include "headers/common.h"
|
||||
#include "headers/descriptor_tables.h"
|
||||
#include "headers/isr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Lets us access our ASM functions from our C code.
|
||||
extern void gdt_flush(uint32_t);
|
||||
extern void idt_flush(uint32_t);
|
||||
// Internal function prototypes.
|
||||
static void init_gdt();
|
||||
static void gdt_set_gate(int,uint32_t,uint32_t,uint8_t,uint8_t);
|
||||
static void init_idt();
|
||||
static void idt_set_gate(uint8_t,uint32_t,uint16_t,uint8_t);
|
||||
gdt_entry_t gdt_entries[5];
|
||||
gdt_ptr_t gdt_ptr;
|
||||
idt_entry_t idt_entries[256];
|
||||
idt_ptr_t idt_ptr;
|
||||
|
||||
// extern the isr handler array so it can nullified on start
|
||||
extern isr_t interrupt_handlers[];
|
||||
|
||||
|
||||
// Initialisation routine - zeroes all the interrupt service routines,
|
||||
// initialises the GDT and IDT.
|
||||
void init_descriptor_tables()
|
||||
{
|
||||
// Initialise the global descriptor table.
|
||||
init_gdt();
|
||||
init_idt();
|
||||
//nullify all the interrupt handlers
|
||||
memset(&interrupt_handlers,0,sizeof(isr_t)*256);
|
||||
}
|
||||
|
||||
static void init_gdt()
|
||||
{
|
||||
gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1;
|
||||
gdt_ptr.base = (uint32_t)&gdt_entries;
|
||||
|
||||
gdt_set_gate(0, 0, 0, 0, 0); // Null segment
|
||||
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment
|
||||
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
|
||||
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
|
||||
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment
|
||||
|
||||
gdt_flush((uint32_t)&gdt_ptr);
|
||||
}
|
||||
|
||||
// Set the value of one GDT entry.
|
||||
static void gdt_set_gate(int num, uint32_t base,uint32_t limit, uint8_t access, uint8_t gran)
|
||||
{
|
||||
gdt_entries[num].base_low = (base & 0xFFFF);
|
||||
gdt_entries[num].base_middle = (base >> 16) & 0xFF;
|
||||
gdt_entries[num].base_high = (base >> 24) & 0xFF;
|
||||
|
||||
gdt_entries[num].limit_low = (limit & 0xFFFF);
|
||||
gdt_entries[num].granularity = (limit >> 16) & 0x0F;
|
||||
|
||||
gdt_entries[num].granularity |= gran & 0xF0;
|
||||
gdt_entries[num].access = access;
|
||||
}
|
||||
|
||||
|
||||
static void init_idt()
|
||||
{
|
||||
idt_ptr.limit = sizeof(idt_entry_t) * 256 -1;
|
||||
idt_ptr.base = (uint32_t)&idt_entries;
|
||||
|
||||
memset(&idt_entries, 0, sizeof(idt_entry_t)*256);
|
||||
|
||||
// Remap the irq table.
|
||||
outb(0x20, 0x11);
|
||||
outb(0xA0, 0x11);
|
||||
outb(0x21, 0x20);
|
||||
outb(0xA1, 0x28);
|
||||
outb(0x21, 0x04);
|
||||
outb(0xA1, 0x02);
|
||||
outb(0x21, 0x01);
|
||||
outb(0xA1, 0x01);
|
||||
outb(0x21, 0x0);
|
||||
outb(0xA1, 0x0);
|
||||
|
||||
|
||||
|
||||
|
||||
idt_set_gate( 0, (uint32_t)isr0 , 0x08, 0x8E);
|
||||
idt_set_gate( 1, (uint32_t)isr1 , 0x08, 0x8E);
|
||||
idt_set_gate( 2, (uint32_t)isr2 , 0x08, 0x8E);
|
||||
idt_set_gate( 3, (uint32_t)isr3 , 0x08, 0x8E);
|
||||
idt_set_gate( 4, (uint32_t)isr4 , 0x08, 0x8E);
|
||||
idt_set_gate( 5, (uint32_t)isr5 , 0x08, 0x8E);
|
||||
idt_set_gate( 6, (uint32_t)isr6 , 0x08, 0x8E);
|
||||
idt_set_gate( 7, (uint32_t)isr7 , 0x08, 0x8E);
|
||||
idt_set_gate( 8, (uint32_t)isr8 , 0x08, 0x8E);
|
||||
idt_set_gate( 9, (uint32_t)isr9 , 0x08, 0x8E);
|
||||
idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E);
|
||||
idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E);
|
||||
idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E);
|
||||
idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E);
|
||||
idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E);
|
||||
idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E);
|
||||
idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E);
|
||||
idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E);
|
||||
idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E);
|
||||
idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E);
|
||||
idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E);
|
||||
idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E);
|
||||
idt_set_gate(22, (uint32_t)isr22, 0x08, 0x8E);
|
||||
idt_set_gate(23, (uint32_t)isr23, 0x08, 0x8E);
|
||||
idt_set_gate(24, (uint32_t)isr24, 0x08, 0x8E);
|
||||
idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E);
|
||||
idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E);
|
||||
idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E);
|
||||
idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E);
|
||||
idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E);
|
||||
idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E);
|
||||
idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E);
|
||||
|
||||
idt_set_gate(32,(uint32_t)irq0,0x08,0x8E);
|
||||
idt_set_gate(33,(uint32_t)irq1,0x08,0x8E);
|
||||
idt_set_gate(34,(uint32_t)irq2,0x08,0x8E);
|
||||
idt_set_gate(35,(uint32_t)irq3,0x08,0x8E);
|
||||
idt_set_gate(36,(uint32_t)irq4,0x08,0x8E);
|
||||
idt_set_gate(37,(uint32_t)irq5,0x08,0x8E);
|
||||
idt_set_gate(38,(uint32_t)irq6,0x08,0x8E);
|
||||
idt_set_gate(39,(uint32_t)irq7,0x08,0x8E);
|
||||
idt_set_gate(40,(uint32_t)irq8,0x08,0x8E);
|
||||
idt_set_gate(41,(uint32_t)irq9,0x08,0x8E);
|
||||
idt_set_gate(42,(uint32_t)irq10,0x08,0x8E);
|
||||
idt_set_gate(43,(uint32_t)irq11,0x08,0x8E);
|
||||
idt_set_gate(44,(uint32_t)irq12,0x08,0x8E);
|
||||
idt_set_gate(45,(uint32_t)irq13,0x08,0x8E);
|
||||
idt_set_gate(46,(uint32_t)irq14,0x08,0x8E);
|
||||
idt_set_gate(47,(uint32_t)irq15,0x08,0x8E);
|
||||
|
||||
|
||||
idt_flush((uint32_t)&idt_ptr);
|
||||
}
|
||||
|
||||
static void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags)
|
||||
{
|
||||
idt_entries[num].base_lo = base & 0xFFFF;
|
||||
idt_entries[num].base_hi = (base >> 16) & 0xFFFF;
|
||||
|
||||
idt_entries[num].sel = sel;
|
||||
idt_entries[num].always0 = 0;
|
||||
// We must uncomment the OR below when we get to using user-mode.
|
||||
// It sets the interrupt gate's privilege level to 3.
|
||||
idt_entries[num].flags = flags /* | 0x60 */;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
28
gdt.s
Normal file
28
gdt.s
Normal file
|
@ -0,0 +1,28 @@
|
|||
;
|
||||
; Gdt.s -- contains global descriptor table and interrupt descriptor table
|
||||
; setup code.
|
||||
; Based on code from Bran's kernel development tutorials.
|
||||
; Rewritten for JamesM's kernel development tutorials.
|
||||
|
||||
[GLOBAL gdt_flush] ; Allows the C code to call gdt_flush().
|
||||
|
||||
gdt_flush:
|
||||
mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter.
|
||||
lgdt [eax] ; Load the new GDT pointer
|
||||
|
||||
mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment
|
||||
mov ds, ax ; Load all data segment selectors
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump!
|
||||
.flush:
|
||||
ret
|
||||
|
||||
[GLOBAL idt_flush] ; Allows the C code to call idt_flush().
|
||||
|
||||
idt_flush:
|
||||
mov eax, [esp+4] ; Get the pointer to the IDT, passed as a parameter.
|
||||
lidt [eax] ; Load the IDT pointer.
|
||||
ret
|
26
headers/common.h
Normal file
26
headers/common.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
//extern void memcpy(void *dest, void *src, unsigned int n);
|
||||
//extern void memset(void *s, int c, unsigned int n);
|
||||
|
||||
//void outb(u16int port, u8int value);
|
||||
//u8int inb(u16int port);
|
||||
//u16int inw(u16int port);
|
||||
extern void memcpy(void *dest, void *src, unsigned int n);
|
||||
extern void memset(void *s, int c, unsigned int n);
|
||||
extern unsigned char inb(unsigned short port);
|
||||
extern void outb(unsigned short port, unsigned char data);
|
||||
extern unsigned short inw(unsigned short port);
|
||||
extern void outw(unsigned short port, unsigned short data);
|
||||
#endif
|
||||
|
||||
|
||||
#define PANIC(msg) panic(msg, __FILE__, __LINE__);
|
||||
#define ASSERT(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b))
|
||||
|
||||
extern void panic(const char *message, const char *file, uint32_t line);
|
||||
extern void panic_assert(const char *file, uint32_t line, const char *desc);
|
114
headers/descriptor_tables.h
Normal file
114
headers/descriptor_tables.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
//
|
||||
// descriptor_tables.h - Defines the interface for initialising the GDT and IDT.
|
||||
// Also defines needed structures.
|
||||
// Based on code from Bran's kernel development tutorials.
|
||||
// Rewritten for JamesM's kernel development tutorials.
|
||||
//
|
||||
|
||||
#include "common.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Initialisation function is publicly accessible.
|
||||
void init_descriptor_tables();
|
||||
|
||||
|
||||
// This structure contains the value of one GDT entry.
|
||||
// We use the attribute 'packed' to tell GCC not to change
|
||||
// any of the alignment in the structure.
|
||||
struct gdt_entry_struct
|
||||
{
|
||||
uint16_t limit_low; // The lower 16 bits of the limit.
|
||||
uint16_t base_low; // The lower 16 bits of the base.
|
||||
uint8_t base_middle; // The next 8 bits of the base.
|
||||
uint8_t access; // Access flags, determine what ring this segment can be used in.
|
||||
uint8_t granularity;
|
||||
uint8_t base_high; // The last 8 bits of the base.
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct gdt_entry_struct gdt_entry_t;
|
||||
|
||||
// This struct describes a GDT pointer. It points to the start of
|
||||
// our array of GDT entries, and is in the format required by the
|
||||
// lgdt instruction.
|
||||
struct gdt_ptr_struct
|
||||
{
|
||||
uint16_t limit; // The upper 16 bits of all selector limits.
|
||||
uint32_t base; // The address of the first gdt_entry_t struct.
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct gdt_ptr_struct gdt_ptr_t;
|
||||
|
||||
// A struct describing an interrupt gate.
|
||||
struct idt_entry_struct
|
||||
{
|
||||
uint16_t base_lo; // The lower 16 bits of the address to jump to when this interrupt fires.
|
||||
uint16_t sel; // Kernel segment selector.
|
||||
uint8_t always0; // This must always be zero.
|
||||
uint8_t flags; // More flags. See documentation.
|
||||
uint16_t base_hi; // The upper 16 bits of the address to jump to.
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct idt_entry_struct idt_entry_t;
|
||||
|
||||
// A struct describing a pointer to an array of interrupt handlers.
|
||||
// This is in a format suitable for giving to 'lidt'.
|
||||
struct idt_ptr_struct
|
||||
{
|
||||
uint16_t limit;
|
||||
uint32_t base; // The address of the first element in our idt_entry_t array.
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct idt_ptr_struct idt_ptr_t;
|
||||
|
||||
// These extern directives let us access the addresses of our ASM ISR handlers.
|
||||
extern void isr0 ();
|
||||
extern void isr1 ();
|
||||
extern void isr2 ();
|
||||
extern void isr3 ();
|
||||
extern void isr4 ();
|
||||
extern void isr5 ();
|
||||
extern void isr6 ();
|
||||
extern void isr7 ();
|
||||
extern void isr8 ();
|
||||
extern void isr9 ();
|
||||
extern void isr10();
|
||||
extern void isr11();
|
||||
extern void isr12();
|
||||
extern void isr13();
|
||||
extern void isr14();
|
||||
extern void isr15();
|
||||
extern void isr16();
|
||||
extern void isr17();
|
||||
extern void isr18();
|
||||
extern void isr19();
|
||||
extern void isr20();
|
||||
extern void isr21();
|
||||
extern void isr22();
|
||||
extern void isr23();
|
||||
extern void isr24();
|
||||
extern void isr25();
|
||||
extern void isr26();
|
||||
extern void isr27();
|
||||
extern void isr28();
|
||||
extern void isr29();
|
||||
extern void isr30();
|
||||
extern void isr31();
|
||||
|
||||
extern void irq0();
|
||||
extern void irq1();
|
||||
extern void irq2();
|
||||
extern void irq3();
|
||||
extern void irq4();
|
||||
extern void irq5();
|
||||
extern void irq6();
|
||||
extern void irq7();
|
||||
extern void irq8();
|
||||
extern void irq9();
|
||||
extern void irq10();
|
||||
extern void irq11();
|
||||
extern void irq12();
|
||||
extern void irq13();
|
||||
extern void irq14();
|
||||
extern void irq15();
|
||||
|
40
headers/isr.h
Normal file
40
headers/isr.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// isr.h -- Interface and structures for high level interrupt service routines.
|
||||
// Part of this code is modified from Bran's kernel development tutorials.
|
||||
// Rewritten for JamesM's kernel development tutorials.
|
||||
//
|
||||
|
||||
#include "common.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct registers
|
||||
{
|
||||
uint32_t ds; // Data segment selector
|
||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha.
|
||||
uint32_t int_no, err_code; // Interrupt number and error code (if applicable)
|
||||
uint32_t eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.
|
||||
} registers_t;
|
||||
|
||||
#define IRQ0 32
|
||||
#define IRQ1 33
|
||||
#define IRQ2 34
|
||||
#define IRQ3 35
|
||||
#define IRQ4 36
|
||||
#define IRQ5 37
|
||||
#define IRQ6 38
|
||||
#define IRQ7 39
|
||||
#define IRQ8 40
|
||||
#define IRQ9 41
|
||||
#define IRQ10 42
|
||||
#define IRQ11 43
|
||||
#define IRQ12 44
|
||||
#define IRQ13 45
|
||||
#define IRQ14 46
|
||||
#define IRQ15 47
|
||||
|
||||
|
||||
// enables registeration of callbacks for interrupts or irqs
|
||||
// for irqs to ease confusin use the #defines ast the first param
|
||||
typedef void (*isr_t)(registers_t*);
|
||||
void register_interrupt_handler(uint8_t n, isr_t handler);
|
||||
|
5
headers/keyboard.h
Normal file
5
headers/keyboard.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void init_keyboard(void);
|
16
headers/kheap.h
Normal file
16
headers/kheap.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include "common.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
uint32_t kmalloc(size_t sz, int align, uint32_t *phys);
|
||||
|
||||
//Allocate a chunk of memory, with size sz.
|
||||
uint32_t kmalloc_a(size_t sz);
|
||||
|
||||
//Allocate a chunk of memory, with size sz. The physical address is returned as phys.
|
||||
uint32_t kmalloc_p(size_t sz, uint32_t *phys);
|
||||
|
||||
//Allocate a chunk of memory, with size sz. The physical address is returned as phys. The memory must be page aligned.
|
||||
uint32_t kmalloc_ap(size_t sz, uint32_t *phys);
|
47
headers/paging.h
Normal file
47
headers/paging.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "isr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct page
|
||||
{
|
||||
uint32_t present : 1; // page present in memory
|
||||
uint32_t rw : 1; // ro if clear, rw if set
|
||||
uint32_t user : 1; // supervisor level only if clear
|
||||
uint32_t accessed : 1; // has been accessed since last referesh
|
||||
uint32_t dirty : 1; // has been written to since last refresh
|
||||
uint32_t unused : 7; // reserved and unused bits
|
||||
uint32_t frame : 20; // frame address (right shift 12 bits)
|
||||
} page_t;
|
||||
|
||||
typedef struct page_table
|
||||
{
|
||||
page_t pages[1024];
|
||||
} page_table_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// array of pointers to pagetables
|
||||
page_table_t *tables[1024];
|
||||
// array of pointers to tables above but at the *physical* loc
|
||||
// so they can be loaded into cr3
|
||||
uint32_t tablesPhysical[1024];
|
||||
|
||||
uint32_t physicalAddr;
|
||||
} page_directory_t;
|
||||
|
||||
// sets up paging
|
||||
void initialize_paging(void);
|
||||
|
||||
// causes the specified page directory to be loaded
|
||||
// into the cr3 register
|
||||
void switch_page_directory(page_directory_t *new);
|
||||
|
||||
// retrieves a pointer to the page requires
|
||||
// if make == 1, if the pagetable in which page
|
||||
// should reside inst there create it
|
||||
page_t *get_page(uint32_t address, int make, page_directory_t *dir);
|
||||
|
||||
// handler for page faults
|
||||
void page_fault(registers_t *regs);
|
45
headers/screen.h
Normal file
45
headers/screen.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef __SCREEN_H
|
||||
#define __SCREEN_H
|
||||
#define VIDEO_ADDRESS 0xb8000
|
||||
#define GREEN_ON_BLACK 0x02
|
||||
|
||||
|
||||
#define FB_COMMAND_PORT 0x3D4
|
||||
#define FB_DATA_PORT 0x3D5
|
||||
// The I/O port commands
|
||||
#define FB_HIGH_BYTE_COMMAND 14
|
||||
#define FB_LOW_BYTE_COMMAND 15
|
||||
|
||||
enum vga_colors {
|
||||
BLACK = 0,
|
||||
BLUE = 1,
|
||||
GREEN = 2,
|
||||
CYAN = 3,
|
||||
RED = 4,
|
||||
MAGENTA = 5,
|
||||
BROWN = 6,
|
||||
LIGHT_GREY = 7,
|
||||
DARK_GREY = 8,
|
||||
LIGHT_BLUE = 9,
|
||||
LIGHT_GREEN = 10,
|
||||
LIGHT_CYAN = 11,
|
||||
LIGHT_RED = 12,
|
||||
LIGHT_MAGENTA = 13,
|
||||
LIGHT_BROWN = 14,
|
||||
WHITE = 15,
|
||||
|
||||
};
|
||||
|
||||
extern void set_current_color(enum vga_colors color);
|
||||
extern void printchar(const char character);
|
||||
extern void print(const char string[]);
|
||||
extern void handle_scrolling();
|
||||
extern void clear();
|
||||
extern void set_cursor(int row, int col);
|
||||
extern void itoa(int num, char *string2);
|
||||
extern void tohex(int val, char *string);
|
||||
extern void kprintf(const char *string, ...); // simple printf style function
|
||||
void zerostring(char *string); // zero out a string needs refactor
|
||||
extern unsigned int strlen(const char *string);
|
||||
// end funciton prototypes
|
||||
#endif
|
62
headers/serial.h
Normal file
62
headers/serial.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#ifndef __SERIAL_H
|
||||
#define __SERIAL_H
|
||||
|
||||
|
||||
#define SERIAL_COM1_BASE 0x3F8 // com1 base port
|
||||
|
||||
|
||||
extern void init_serial();
|
||||
|
||||
|
||||
/** serial_configure_baud_rate:
|
||||
* Sets the speed of the data being sent. The default speed of a serial
|
||||
* port is 115200 bits/s. The argument is a divisor of that number, hence
|
||||
* the resulting speed becomes (115200 / divisor) bits/s.
|
||||
*
|
||||
* @param com The COM port to configure
|
||||
* @param divisor The divisor
|
||||
*/
|
||||
|
||||
extern void serial_configure_baud_rate(unsigned short com, unsigned short divisor);
|
||||
|
||||
// configures line of a serial port
|
||||
extern void serial_configure_line(unsigned short com);
|
||||
|
||||
|
||||
|
||||
// Bit: | 7 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
// Content: | lvl | bs | r | dma | clt | clr | e |
|
||||
// 0xc7
|
||||
/*
|
||||
*Enables FIFO
|
||||
*Clear both receiver and transmission FIFO queues
|
||||
*Use 14 bytes as size of queue
|
||||
*/
|
||||
extern void serial_configure_buffers(unsigned short com);
|
||||
|
||||
// write data into the serial port
|
||||
extern void serial_write(unsigned short com, char data);
|
||||
|
||||
|
||||
// configure the modem of our serial port
|
||||
// Bit: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
// Content: | r | r | af | lb | ao2 | ao1 | rts | dtr |
|
||||
extern void serial_configure_modem(unsigned short com);
|
||||
|
||||
|
||||
/** serial_is_transmit_fifo_empty:
|
||||
* Checks whether the transmit FIFO queue is empty or not for the given COM
|
||||
* port.
|
||||
*
|
||||
* @param com The COM port
|
||||
* @return 0 if the transmit FIFO queue is not empty
|
||||
* 1 if the transmit FIFO queue is empty
|
||||
*/
|
||||
extern int serial_is_trasmit_fifo_empty(unsigned short com);
|
||||
|
||||
|
||||
extern void serial_print(char *string); // print out over a serial port
|
||||
|
||||
// printf style func for serial port
|
||||
void serial_printf(char *format, ...);
|
||||
#endif
|
6
headers/timer.h
Normal file
6
headers/timer.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void init_timer(uint32_t frequency);
|
159
interrupt.s
Normal file
159
interrupt.s
Normal file
|
@ -0,0 +1,159 @@
|
|||
;
|
||||
; interrupt.s -- Contains interrupt service routine wrappers.
|
||||
; Based on Bran's kernel development tutorials.
|
||||
; Rewritten for JamesM's kernel development tutorials.
|
||||
|
||||
; This macro creates a stub for an ISR which does NOT pass it's own
|
||||
; error code (adds a dummy errcode byte).
|
||||
%macro ISR_NOERRCODE 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
cli ; Disable interrupts firstly.
|
||||
push byte 0 ; Push a dummy error code.
|
||||
push byte %1 ; Push the interrupt number.
|
||||
jmp isr_common_stub ; Go to our common handler code.
|
||||
%endmacro
|
||||
|
||||
; This macro creates a stub for an ISR which passes it's own
|
||||
; error code.
|
||||
%macro ISR_ERRCODE 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
cli ; Disable interrupts.
|
||||
push byte %1 ; Push the interrupt number
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
%macro IRQ 2
|
||||
global irq%1
|
||||
irq%1:
|
||||
cli
|
||||
push byte 0
|
||||
push byte %2
|
||||
jmp irq_common_stub
|
||||
%endmacro
|
||||
|
||||
|
||||
|
||||
ISR_NOERRCODE 0
|
||||
ISR_NOERRCODE 1
|
||||
ISR_NOERRCODE 2
|
||||
ISR_NOERRCODE 3
|
||||
ISR_NOERRCODE 4
|
||||
ISR_NOERRCODE 5
|
||||
ISR_NOERRCODE 6
|
||||
ISR_NOERRCODE 7
|
||||
ISR_ERRCODE 8
|
||||
ISR_NOERRCODE 9
|
||||
ISR_ERRCODE 10
|
||||
ISR_ERRCODE 11
|
||||
ISR_ERRCODE 12
|
||||
ISR_ERRCODE 13
|
||||
ISR_ERRCODE 14
|
||||
ISR_NOERRCODE 15
|
||||
ISR_NOERRCODE 16
|
||||
ISR_ERRCODE 17
|
||||
ISR_NOERRCODE 18
|
||||
ISR_NOERRCODE 19
|
||||
ISR_NOERRCODE 20
|
||||
ISR_NOERRCODE 21
|
||||
ISR_NOERRCODE 22
|
||||
ISR_NOERRCODE 23
|
||||
ISR_NOERRCODE 24
|
||||
ISR_NOERRCODE 25
|
||||
ISR_NOERRCODE 26
|
||||
ISR_NOERRCODE 27
|
||||
ISR_NOERRCODE 28
|
||||
ISR_NOERRCODE 29
|
||||
ISR_ERRCODE 30
|
||||
ISR_NOERRCODE 31
|
||||
IRQ 0, 32
|
||||
IRQ 1, 33
|
||||
IRQ 2, 34
|
||||
IRQ 3, 35
|
||||
IRQ 4, 36
|
||||
IRQ 5, 37
|
||||
IRQ 6, 38
|
||||
IRQ 7, 39
|
||||
IRQ 8, 40
|
||||
IRQ 9, 41
|
||||
IRQ 10, 42
|
||||
IRQ 11, 43
|
||||
IRQ 12, 44
|
||||
IRQ 13, 45
|
||||
IRQ 14, 46
|
||||
IRQ 15, 47
|
||||
|
||||
|
||||
|
||||
; In isr.c
|
||||
extern isr_handler
|
||||
|
||||
; This is our common ISR stub. It saves the processor state, sets
|
||||
; up for kernel mode segments, calls the C-level fault handler,
|
||||
; and finally restores the stack frame.
|
||||
isr_common_stub:
|
||||
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
|
||||
|
||||
|
||||
mov ax, ds ; Lower 16-bits of eax = ds.
|
||||
push eax ; save the data segment descriptor
|
||||
|
||||
mov ax, 0x10 ; load the kernel data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
push esp ; registers_t *r
|
||||
|
||||
; c following sys v requires df to be clear on func entry
|
||||
cld
|
||||
|
||||
call isr_handler
|
||||
|
||||
pop eax ; remove our pointer
|
||||
pop eax ; reload the original data segment descriptor
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
mov fs, bx
|
||||
mov gs, bx
|
||||
|
||||
popa ; Pops edi,esi,ebp...
|
||||
add esp, 8
|
||||
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
|
||||
|
||||
|
||||
; In isr.c
|
||||
extern irq_handler
|
||||
|
||||
; our common irq stub. it saves the processor state, sets
|
||||
; up for kernel mode segments, calls the c level fault handler
|
||||
; and finally restores the stack frame.
|
||||
irq_common_stub:
|
||||
pusha ; push edi,esi,ebp,esp,ebx,edx,ecx,eax
|
||||
|
||||
mov ax, ds ; lower 16-bits of eax = ds
|
||||
push eax ; save the segment descriptor
|
||||
|
||||
mov ax, 0x10 ; load the kernel data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
push esp
|
||||
cld
|
||||
|
||||
call irq_handler
|
||||
|
||||
|
||||
pop ebx ; remove esp
|
||||
pop ebx ; reload the original ds descriptor different than the isr code
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
mov fs, bx
|
||||
mov gs, bx
|
||||
|
||||
popa
|
||||
add esp, 8 ;; cleans up the pushed error code and isr number
|
||||
iret ; pops cs eip eflags ss and esp
|
||||
|
5
iso/boot/grub/menu.lst
Normal file
5
iso/boot/grub/menu.lst
Normal file
|
@ -0,0 +1,5 @@
|
|||
defualt=0
|
||||
timeout=0
|
||||
|
||||
title ProjectRED
|
||||
kernel /boot/kernel.elf
|
BIN
iso/boot/grub/stage2_eltorito
Normal file
BIN
iso/boot/grub/stage2_eltorito
Normal file
Binary file not shown.
50
isr.c
Normal file
50
isr.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// isr.c -- High level interrupt service routines and interrupt request handlers.
|
||||
// Part of this code is modified from Bran's kernel development tutorials.
|
||||
// Rewritten for JamesM's kernel development tutorials.
|
||||
//
|
||||
|
||||
#include "headers/common.h"
|
||||
#include "headers/isr.h"
|
||||
#include "headers/screen.h"
|
||||
#include <stdint.h>
|
||||
|
||||
isr_t interrupt_handlers[256];
|
||||
|
||||
|
||||
// This gets called from our ASM interrupt handler stub.
|
||||
void isr_handler(registers_t *regs)
|
||||
{
|
||||
//kprintf("recieved interrupt: %d\n",regs->int_no);
|
||||
|
||||
if(interrupt_handlers[regs->int_no] != 0)
|
||||
{
|
||||
isr_t handler = interrupt_handlers[regs->int_no];
|
||||
handler(regs);
|
||||
}
|
||||
}
|
||||
|
||||
void irq_handler(registers_t *regs)
|
||||
{
|
||||
//kprintf("recieved irq: %d\n",regs->int_no);
|
||||
// send an EOI signal to pics if this
|
||||
// interrupt involved the slave
|
||||
if(regs->int_no >= 40)
|
||||
{
|
||||
outb(0xA0,0x20);
|
||||
}
|
||||
// send reset siginal to master. (as well as slave, if neccessary).
|
||||
outb(0x20,0x20);
|
||||
|
||||
if(interrupt_handlers[regs->int_no] != 0)
|
||||
{
|
||||
isr_t handler = interrupt_handlers[regs->int_no];
|
||||
handler(regs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void register_interrupt_handler(uint8_t n, isr_t handler)
|
||||
{
|
||||
interrupt_handlers[n] = handler;
|
||||
}
|
48
keyboard.c
Normal file
48
keyboard.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include "headers/isr.h"
|
||||
#include "headers/common.h"
|
||||
#include "headers/screen.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
// make an array for the keystate
|
||||
// aswell as a struct for the state of toggle keys
|
||||
// and other ones such as shift ctrl etc
|
||||
|
||||
// add polling of status bits to recieve input properly
|
||||
extern uint8_t current_color;
|
||||
static void keyboard_callback(registers_t *regs)
|
||||
{
|
||||
regs->eax++; // lul
|
||||
uint8_t scancode = inb(0x60); // read from the 8042 PS/2 data port
|
||||
|
||||
static int i = 0;
|
||||
static int j = 0;
|
||||
j = j%15;
|
||||
current_color = j++;
|
||||
kprintf("keyboard event 0x%x : %d\n",scancode,scancode);
|
||||
i++;
|
||||
|
||||
|
||||
// check for key presses like shift
|
||||
// else use a lookup table to print it dependant on the state
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void init_keyboard(void)
|
||||
{
|
||||
// register our keyboard callback
|
||||
register_interrupt_handler(IRQ1,&keyboard_callback);
|
||||
|
||||
// poll until buffer is empty
|
||||
bool full = true;
|
||||
while(full)
|
||||
{
|
||||
full = inb(0x64) & 1; // poll bit 1 of status reg
|
||||
}
|
||||
|
||||
// send a scancode change request
|
||||
outb(0x60,0xF0); //scan code change
|
||||
outb(0x60,0x2); // set 2
|
||||
}
|
40
kheap.c
Normal file
40
kheap.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "headers/kheap.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// end is defined in the linker
|
||||
extern uint32_t end;
|
||||
uint32_t placement_address = (uint32_t)&end;
|
||||
|
||||
uint32_t kmalloc(size_t sz, int align, uint32_t *phys)
|
||||
{
|
||||
if( align == 1 && (placement_address & 0xFFFFF000)) // if not page aligned
|
||||
{
|
||||
placement_address &= 0xFFFFF000;
|
||||
placement_address += 0x1000;
|
||||
}
|
||||
if(phys)
|
||||
{
|
||||
*phys = placement_address;
|
||||
}
|
||||
uint32_t tmp = placement_address;
|
||||
placement_address += sz;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t kmalloc_a(size_t sz)
|
||||
{
|
||||
return kmalloc(sz,1,0);
|
||||
}
|
||||
|
||||
uint32_t kmalloc_p(size_t sz, uint32_t *phys)
|
||||
{
|
||||
return kmalloc(sz,0,phys);
|
||||
}
|
||||
|
||||
uint32_t kmalloc_ap(size_t sz, uint32_t *phys)
|
||||
{
|
||||
return kmalloc(sz,1,phys);
|
||||
}
|
33
link.ld
Normal file
33
link.ld
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* Link.ld -- Linker script for the kernel - ensure everything goes in the */
|
||||
/* Correct place. */
|
||||
/* Original file taken from Bran's Kernel Development */
|
||||
/* tutorials: http://www.osdever.net/bkerndev/index.php. */
|
||||
|
||||
ENTRY(start)
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
.text 0x100000 :
|
||||
{
|
||||
code = .; _code = .; __code = .;
|
||||
*(.text)
|
||||
. = ALIGN(4096);
|
||||
}
|
||||
|
||||
.data :
|
||||
{
|
||||
data = .; _data = .; __data = .;
|
||||
*(.data)
|
||||
*(.rodata)
|
||||
. = ALIGN(4096);
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
bss = .; _bss = .; __bss = .;
|
||||
*(.bss)
|
||||
. = ALIGN(4096);
|
||||
}
|
||||
|
||||
end = .; _end = .; __end = .;
|
||||
}
|
71
main.c
Normal file
71
main.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
// add something that instructs the compiler to ignore unused vars
|
||||
// for ones that we aernt using yet
|
||||
#include "headers/descriptor_tables.h"
|
||||
#include "headers/screen.h"
|
||||
#include "headers/serial.h"
|
||||
#include "headers/timer.h"
|
||||
#include "headers/keyboard.h"
|
||||
#include "headers/paging.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
void gpt(registers_t *regs)
|
||||
{
|
||||
regs->eax++;
|
||||
PANIC("General protection fault");
|
||||
}
|
||||
|
||||
extern uint8_t current_color;
|
||||
int kernel_main(void)
|
||||
{
|
||||
register_interrupt_handler(13, &gpt);
|
||||
|
||||
//Prepare the screen, and make sure the colors are set proper.
|
||||
clear();
|
||||
set_current_color(WHITE);
|
||||
|
||||
print("Intializing kernel...\n");
|
||||
|
||||
//Initialize and test the serial port.
|
||||
init_serial();
|
||||
serial_print("Serial logging started!\n");
|
||||
print("Serial Initialized.\n");
|
||||
|
||||
// Initialise all the ISRs and segmentation
|
||||
init_descriptor_tables();
|
||||
print("Descriptor tables Initialized.\n");
|
||||
|
||||
//Prepare paging. TODO: Finish Michael's implementation
|
||||
//initialize_paging();
|
||||
print("Paging ready.\n");
|
||||
|
||||
//Get the timer ready
|
||||
//init_timer(0);
|
||||
|
||||
//Prepare the keyboard for taking input.#
|
||||
asm("sti");
|
||||
init_keyboard(); //<--- come back to after basic memory allocation
|
||||
print("Keyboard ready.\n");
|
||||
|
||||
//This should cause a page fault and thus a panic.
|
||||
|
||||
volatile uint32_t *ptr = (uint32_t*)NULL;
|
||||
kprintf("(0x%x)*ptr = %x\n",ptr,&ptr);
|
||||
|
||||
//Print our fancy colored message.
|
||||
set_current_color(GREEN);
|
||||
print("(c)");
|
||||
set_current_color(WHITE);
|
||||
print("Project");
|
||||
set_current_color(RED);
|
||||
print("RED");
|
||||
set_current_color(WHITE);
|
||||
print(", 2019\n");
|
||||
|
||||
|
||||
|
||||
//Hang.
|
||||
for(;;) {}
|
||||
return 0;
|
||||
}
|
52
makefile
Normal file
52
makefile
Normal file
|
@ -0,0 +1,52 @@
|
|||
C_SOURCES = $(wildcard *.c)
|
||||
ASM_SOURCES = $(wildcard *.s)
|
||||
HEADERS = $(wildcard headers/*.h)
|
||||
#OBJECTS = loader.o ${C_SOURCES:.c=.o}
|
||||
#OBJECTS = ${C_SOURCES:.c=.o ASM_SOURCES:.s=.o}
|
||||
OBJECTS = ${ASM_SOURCES:.s=.o} ${C_SOURCES:.c=.o}
|
||||
#OBJECTS = ${wildcard *.o}
|
||||
CC = i686-elf-gcc
|
||||
CFLAGS = -masm=intel -m32 -ffreestanding -fno-builtin -fno-stack-protector \
|
||||
-isystem=/usr/include -Wall -Wextra -Werror -c
|
||||
LDFLAGS = -T link.ld -melf_i386
|
||||
AS = nasm
|
||||
ASFLAGS = -f elf32
|
||||
|
||||
everything: all
|
||||
rm -f os.iso
|
||||
cp kernel.elf iso/boot/kernel.elf
|
||||
genisoimage -R \
|
||||
-b boot/grub/stage2_eltorito \
|
||||
-no-emul-boot \
|
||||
-A os \
|
||||
-input-charset utf8 \
|
||||
-quiet \
|
||||
-boot-info-table \
|
||||
-o os.iso \
|
||||
iso
|
||||
|
||||
all: kernel.elf
|
||||
|
||||
kernel.elf: $(OBJECTS)
|
||||
i686-elf-ld $(LDFLAGS) $(OBJECTS) -o kernel.elf
|
||||
|
||||
os.iso: kernel.elf
|
||||
cp kernel.elf iso/boot/kernel.elf
|
||||
genisoimage -R \
|
||||
-b boot/grub/stage2_eltorito \
|
||||
-no-emul-boot \
|
||||
-A os \
|
||||
-input-charset utf8 \
|
||||
-quiet \
|
||||
-boot-info-table \
|
||||
-o os.iso \
|
||||
iso
|
||||
|
||||
%.o: %.c ${HEADERS}
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
%.o: %.s
|
||||
$(AS) $(ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
clean:
|
||||
rm *.o
|
218
paging.c
Normal file
218
paging.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
#include "headers/paging.h"
|
||||
#include "headers/kheap.h"
|
||||
#include "headers/screen.h"
|
||||
#include "headers/serial.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// The kernel's page directory
|
||||
page_directory_t *kernel_directory=0;
|
||||
|
||||
// The current page directory;
|
||||
page_directory_t *current_directory=0;
|
||||
|
||||
|
||||
// a bitset of frames - used or free
|
||||
uint32_t *frames;
|
||||
uint32_t nframes;
|
||||
|
||||
// defined in kheap.c
|
||||
extern uint32_t placement_address;
|
||||
|
||||
// Macros for bitset algo's
|
||||
#define INDEX_FROM_BIT(a) (a/(8*4))
|
||||
#define OFFSET_FROM_BIT(a) (a%(8*4))
|
||||
|
||||
// set a bit in the frames bitset
|
||||
static void set_frame(uint32_t frame_addr)
|
||||
{
|
||||
uint32_t frame = frame_addr/0x1000;
|
||||
uint32_t idx = INDEX_FROM_BIT(frame);
|
||||
uint32_t off = OFFSET_FROM_BIT(frame);
|
||||
frames[idx] &= ~(0x1 << off);
|
||||
}
|
||||
|
||||
// clear frame in a bitset
|
||||
static void clear_frame(uint32_t frame_addr)
|
||||
{
|
||||
uint32_t frame = frame_addr/0x1000;
|
||||
uint32_t idx = INDEX_FROM_BIT(frame);
|
||||
uint32_t off = OFFSET_FROM_BIT(frame);
|
||||
frames[idx] &= ~(0x1 << off);
|
||||
}
|
||||
|
||||
/*// test if a bit is set
|
||||
static u32int test_frame(uint32_t frame_addr)
|
||||
{
|
||||
uint32_t frame = frame_addr/0x1000;
|
||||
uint32_t idx = INDEX_FROM_BIT(frame);
|
||||
uint32_t off = OFFSET_FROM_BIT(frame);
|
||||
return (frames[idx] & (0x1 << off));
|
||||
} */
|
||||
|
||||
// find the first free frame
|
||||
static uint32_t first_frame()
|
||||
{
|
||||
uint32_t i, j;
|
||||
for(i = 0; i < INDEX_FROM_BIT(nframes); i++)
|
||||
{
|
||||
if(frames[i] != 0xFFFFFFFF) // nothing free exit early
|
||||
{
|
||||
// atleast one bit is free
|
||||
for(j = 0; j < 32; j++)
|
||||
{
|
||||
uint32_t toTest = 0x1 << j;
|
||||
if(!(frames[i]&toTest))
|
||||
{
|
||||
return i*4*8+j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// alloc a frame
|
||||
void alloc_frame(page_t *page, int is_kernel, int is_writeable)
|
||||
{
|
||||
if(page->frame != 0)
|
||||
{
|
||||
return; // frame allready alloced
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t idx = first_frame(); // idx now index for first free frame
|
||||
if(idx == (uint32_t)-1)
|
||||
{
|
||||
PANIC("No free frames!");
|
||||
}
|
||||
set_frame(idx*0x1000); // frame is now ours
|
||||
page->present = 1; // mark as present
|
||||
page->rw = (is_writeable)?1:0; // should page be w
|
||||
page->user = (is_kernel)?0:1; // should page be user-mode
|
||||
page->frame = idx;
|
||||
}
|
||||
}
|
||||
|
||||
// function to dealloc a frame
|
||||
void free_frame(page_t * page)
|
||||
{
|
||||
uint32_t frame;
|
||||
if(!(frame=page->frame))
|
||||
{
|
||||
return; // page didnt actually have a alloced frame
|
||||
}
|
||||
else
|
||||
{
|
||||
clear_frame(frame); // free the frame
|
||||
page->frame = 0x0; // page has no frame
|
||||
}
|
||||
}
|
||||
|
||||
void initialize_paging()
|
||||
{
|
||||
//size of physcial mem for now we assume it is 16MB
|
||||
uint32_t mem_end_page = 0x1000000;
|
||||
|
||||
nframes = mem_end_page / 0x1000;
|
||||
frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes),0,0);
|
||||
memset(frames,0,INDEX_FROM_BIT(nframes));
|
||||
|
||||
// lets make a page directory <--- cont here
|
||||
kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
|
||||
memset(kernel_directory, 0, sizeof(page_directory_t));
|
||||
current_directory = kernel_directory;
|
||||
|
||||
|
||||
// my need to identify map (phys addr = virt addr from
|
||||
// 0x0 to end of used mem so this can be accessed transparently
|
||||
// as if paging isnt enabled
|
||||
uint32_t i = 0;
|
||||
while(i < placement_address)
|
||||
{
|
||||
// read but not writeable from user space
|
||||
alloc_frame(get_page(i,1,kernel_directory),0,0);
|
||||
i += 0x1000;
|
||||
}
|
||||
|
||||
// before we enable paging set our page fault handler
|
||||
register_interrupt_handler(14, &page_fault);
|
||||
|
||||
|
||||
// enable paging! <-- should have a seperate function
|
||||
// for the first time this is done and not constantly renable it
|
||||
switch_page_directory(kernel_directory);
|
||||
print("Paging enabled!\n");
|
||||
}
|
||||
|
||||
|
||||
void switch_page_directory(page_directory_t *dir)
|
||||
{
|
||||
current_directory = dir;
|
||||
asm volatile("mov cr3, %0":: "r"(&dir->tablesPhysical));
|
||||
uint32_t cr0;
|
||||
asm volatile("mov %0, cr0": "=r"(cr0));
|
||||
serial_printf("cr0 = %x\n",cr0);
|
||||
cr0 |= 0x80000000; // Enable paging!
|
||||
asm volatile("mov cr0, %0":: "r"(cr0));
|
||||
}
|
||||
|
||||
|
||||
page_t *get_page(uint32_t address, int make, page_directory_t *dir)
|
||||
{
|
||||
// turn address into an index
|
||||
address /= 0x1000;
|
||||
|
||||
// find the page table that contains this address
|
||||
uint32_t table_idx = address / 1024;
|
||||
if(dir->tables[table_idx]) // if this page is allready assigned
|
||||
{
|
||||
return &dir->tables[table_idx]->pages[address%1024];
|
||||
}
|
||||
else if(make)
|
||||
{
|
||||
uint32_t tmp;
|
||||
dir->tables[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp);
|
||||
memset(dir->tables[table_idx], 0, 0x1000);
|
||||
dir->tablesPhysical[table_idx] = tmp | 0x7; // PRESENT, RW, US.
|
||||
return &dir->tables[table_idx]->pages[address%1024];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// fix issue with page fault passing see
|
||||
// Problem: Interrupt handlers corrupt interrupted state
|
||||
// & Problem 3: regs var must called by reference instead of by value in the irq and isr handlers
|
||||
void page_fault(registers_t *regs)
|
||||
{
|
||||
// a page fault has occured
|
||||
// faulting address is in cr2
|
||||
uint32_t faulting_address;
|
||||
asm volatile("mov %0, cr2" : "=r" (faulting_address));
|
||||
|
||||
// the error codes gives us details of what happened
|
||||
int present = !(regs->err_code & 0x1); // Page not present
|
||||
int rw = regs->err_code & 0x2; // Write operation?
|
||||
int us = regs->err_code & 0x4; // Processor was in user-mode?
|
||||
int reserved = regs->err_code & 0x8; // Overwritten CPU-reserved bits of page entry?
|
||||
int id = regs->err_code & 0x10; // Caused by an instruction fetch?
|
||||
|
||||
|
||||
// output an error message
|
||||
print("Page fault! ( ");
|
||||
if(present) { print("present "); }
|
||||
else if(rw) { print("read-only "); }
|
||||
else if(us) { print("user-mode "); }
|
||||
else if(id) { print("instr-fetch "); }
|
||||
else if(reserved) {print("reserved "); }
|
||||
kprintf(") at 0x%x\n",faulting_address);
|
||||
PANIC("Page fault");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
277
screen.c
Normal file
277
screen.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
#include "headers/screen.h"
|
||||
#include "headers/common.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
volatile uint16_t* vga_buffer = (uint16_t*) 0xB8000;
|
||||
|
||||
uint8_t current_color;
|
||||
|
||||
void set_current_color(enum vga_colors color) {
|
||||
current_color = color;
|
||||
}
|
||||
|
||||
/* Entries of the VGA Buffer take the form BBBBFFFFCCCCCCCC
|
||||
* BBBB = Background Color
|
||||
* FFFF = Foreground Color
|
||||
* CCCCCCCC = Character code
|
||||
*/
|
||||
|
||||
//Get the 8 color bits from the above enumerator
|
||||
static inline uint8_t vga_entry_color(enum vga_colors fg, enum vga_colors bg) {
|
||||
return fg | bg << 4; //Shift the background to the left, then OR with fg to add them together.
|
||||
}
|
||||
//Apply the color bits to make a printed character
|
||||
static inline uint16_t vga_entry(unsigned char uc, uint8_t color) {
|
||||
return (uint16_t) uc | (uint16_t) color << 8; //Same here - shift the color to the left, then OR with the character to append.
|
||||
}
|
||||
|
||||
int i; // offset to framebuffer
|
||||
uint8_t row; // current row between 1-25
|
||||
uint8_t col; // current col between 1-80
|
||||
short calc = 0; // random var for various calcs must be initialized or cleaned after func calls
|
||||
// ^ attempt at packing may need calc to be an int however...
|
||||
|
||||
// simple printf style function(needs testing with errenous data)
|
||||
// add tab support and %p specifier
|
||||
// also add support for printing the register state
|
||||
void kprintf(const char *string, ...) // look up how this is properly done
|
||||
{
|
||||
int j = 0;
|
||||
int num = 0; // number to hold our stuff :)
|
||||
char string2[11] = {0}; // string for printing ints :)
|
||||
|
||||
/* list stuff :) */
|
||||
va_list ap;
|
||||
// find how many things we are parsing
|
||||
|
||||
va_start(ap, string);
|
||||
|
||||
while(string[j] != 0)
|
||||
{
|
||||
if(string[j] == '%') // if a format specifier
|
||||
{
|
||||
if(string[j+1] == 'd') // print a decimal
|
||||
{
|
||||
num = va_arg(ap, int);
|
||||
itoa(num, string2); // account for negatives...
|
||||
print(string2);
|
||||
zerostring(string2);
|
||||
j += 2;
|
||||
}
|
||||
|
||||
else if(string[j+1] == 'x') // print as hex
|
||||
{
|
||||
num = va_arg(ap, int);
|
||||
tohex(num, string2);
|
||||
print(string2);
|
||||
zerostring(string2);
|
||||
j += 2;
|
||||
}
|
||||
|
||||
else if(string[j+1] == 's') // print a string
|
||||
{
|
||||
print(va_arg(ap, char*));
|
||||
j += 2;
|
||||
}
|
||||
|
||||
else if(string[j+1] == 'c') // print a char
|
||||
{
|
||||
char c = va_arg(ap,int);
|
||||
printchar(c);
|
||||
j += 2;
|
||||
}
|
||||
|
||||
else // unknown format string
|
||||
{
|
||||
//serial_printf("[ERROR]attempted to parse unknown format string\n");
|
||||
return; // prevent undefined behaviour
|
||||
}
|
||||
}
|
||||
|
||||
else // is a regular character
|
||||
{
|
||||
printchar(string[j]);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
va_end(ap); // clean up variable length list
|
||||
}
|
||||
|
||||
void printchar(char character) {
|
||||
|
||||
switch (character) {
|
||||
case '\n': { //For newline, move to next row and focus on the first character.
|
||||
col = 0;
|
||||
row++;
|
||||
break;
|
||||
}
|
||||
default: { // All other characters simply get written to the buffer.
|
||||
const size_t i = (row * 80) + col; //i = index
|
||||
vga_buffer[i] = ((uint16_t) current_color << 8) | character;
|
||||