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;
|
||||||
|
col++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(col > 79) // keep track of row and column for scrolling and newlines
|
||||||
|
{
|
||||||
|
col = 0;
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(row > 25)
|
||||||
|
{
|
||||||
|
handle_scrolling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void print(const char *string) {
|
||||||
|
unsigned int len = strlen(string); // may be better to pass len as an arg
|
||||||
|
unsigned int j = 0;
|
||||||
|
while(j < len)
|
||||||
|
{
|
||||||
|
printchar(string[j]);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill screen with spaces, effectively clearing the screen.
|
||||||
|
void clear() {
|
||||||
|
unsigned char *vga_memory = (unsigned char *) vga_buffer;
|
||||||
|
for(int j = 0; j < 4001; j = j + 2) // 80 * 25 * 2 =4000(end of framebuffer)
|
||||||
|
{
|
||||||
|
vga_memory[j] = 0x20; // assign a space to current pos
|
||||||
|
vga_memory[j + 1] = 0x00; // clear the attribute
|
||||||
|
}
|
||||||
|
row = 0;
|
||||||
|
col = 0;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// note learn how inline asm works properly
|
||||||
|
void set_cursor(int row, int col) {
|
||||||
|
unsigned short position=(row*80) + col;
|
||||||
|
outb(0x3D4, 0X0F);
|
||||||
|
outb(0x3D5, (unsigned char)(position&0xff));
|
||||||
|
outb(0x3D4, 0x0E);
|
||||||
|
outb(0x3D5, (unsigned char)((position>>8)&0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// scroll the screen when it gets to the last line
|
||||||
|
void handle_scrolling(){
|
||||||
|
int x = 160; // start of 2nd line
|
||||||
|
|
||||||
|
unsigned char *vga_memory = (unsigned char *) vga_buffer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
while(x < 4001) { // max each char is 2 apart
|
||||||
|
vga_memory[x-160] = vga_memory[x]; //Move every character up a line
|
||||||
|
vga_memory[x-159] = vga_memory[x+1]; //Move the character attributes too
|
||||||
|
x += 2; //Move to next character
|
||||||
|
}
|
||||||
|
x = 3840; //Start of the last line
|
||||||
|
|
||||||
|
for(i = 1920; i < 2001; i++) { // Memory locations for the characters in the last line
|
||||||
|
vga_memory[x] = 0; //Set current character to 0 (null)
|
||||||
|
x += 2; // Move to next character
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 3840; // set i to start of last line
|
||||||
|
row = 24; // set row to 25 so when a \n is printed the screen will scroll
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void itoa(int num, char *string2) {// convert from int to ascii eqiv
|
||||||
|
|
||||||
|
int j = 0; // counter
|
||||||
|
calc = 0; //Result of a calculation
|
||||||
|
bool flag_negative = false;
|
||||||
|
|
||||||
|
|
||||||
|
if(num == 0) { // catch 0
|
||||||
|
string2[0] = '0';
|
||||||
|
string2[1] = '\0'; // null term
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num < 0) {
|
||||||
|
flag_negative = true;
|
||||||
|
num = -num; //invert it so it calcs
|
||||||
|
}
|
||||||
|
|
||||||
|
while(num != 0) {// while we can still divide
|
||||||
|
|
||||||
|
calc = num % 10; // get raminder in calc
|
||||||
|
num = num / 10; // div by 10
|
||||||
|
calc += 48; // convert to ascii
|
||||||
|
//printchar(calc);
|
||||||
|
string2[j] = calc;
|
||||||
|
j++; // inc amount of chars to print
|
||||||
|
|
||||||
|
}
|
||||||
|
if(flag_negative) {
|
||||||
|
string2[j] = '-';
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i<j/2; i++) {
|
||||||
|
calc = string2[i];
|
||||||
|
string2[i] = string2[j-i-1];
|
||||||
|
string2[j-i-1] = calc;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert a number to a hex
|
||||||
|
void tohex(int val, char *string) {
|
||||||
|
zerostring(string);
|
||||||
|
uint8_t j = 8;
|
||||||
|
uint8_t temp = 0;
|
||||||
|
while(j != 0) {
|
||||||
|
j--; // decerment j
|
||||||
|
temp = val & 0xf; // get just nibble into temp
|
||||||
|
val = val >> 4; // shr val four so that it loses char
|
||||||
|
if(temp >= 10) {
|
||||||
|
temp += 7; // if higher than 10 convert to letter
|
||||||
|
}
|
||||||
|
temp += 48; //convert to ascii
|
||||||
|
string[j] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the string pointer with 0 (null) characters
|
||||||
|
void zerostring(char *string) {
|
||||||
|
unsigned int len = strlen(string);
|
||||||
|
for(unsigned int i = 0; i <= len; i++)
|
||||||
|
{
|
||||||
|
string[i] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int strlen(const char *string) {
|
||||||
|
unsigned int len = 0;
|
||||||
|
while(string[len])
|
||||||
|
{
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print out registers for debugging
|
||||||
|
/*void writeregs(void)
|
||||||
|
{
|
||||||
|
unsigned int Register = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}*/
|
171
serial.c
Normal file
171
serial.c
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
#include "headers/common.h"
|
||||||
|
#include "headers/screen.h" // for conversion functions(maybye put in seperate header)
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define SERIAL_DATA_PORT(base) (base)
|
||||||
|
#define SERIAL_FIFO_COMMAND_PORT(base) (base + 2)
|
||||||
|
#define SERIAL_LINE_COMMAND_PORT(base) (base + 3)
|
||||||
|
#define SERIAL_MODEM_COMMAND_PORT(base) (base + 4)
|
||||||
|
#define SERIAL_LINE_STATUS_PORT(base) (base + 5)
|
||||||
|
#define SERIAL_COM1_BASE 0x3F8 // com1 base port
|
||||||
|
|
||||||
|
// SERIAL_LINE_ENABLE_DLAB:
|
||||||
|
// tells the serial port to expect high byte first
|
||||||
|
// then the low order byte follows
|
||||||
|
|
||||||
|
#define SERIAL_LINE_ENABLE_DLAB 0x80
|
||||||
|
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
void serial_configure_baud_rate(unsigned short com, unsigned short divisor)
|
||||||
|
{
|
||||||
|
outb(SERIAL_LINE_COMMAND_PORT(com),
|
||||||
|
SERIAL_LINE_ENABLE_DLAB);
|
||||||
|
outb(SERIAL_DATA_PORT(com),
|
||||||
|
(divisor >> 8) & 0x00ff);
|
||||||
|
outb(SERIAL_DATA_PORT(com),
|
||||||
|
divisor & 0x00ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// configures line of a serial port
|
||||||
|
void serial_configure_line(unsigned short com)
|
||||||
|
{
|
||||||
|
/* Bit: | 7 | 6 | 5 4 3 | 2 | 1 0 |
|
||||||
|
* Content: | d | b | prty | s | dl |
|
||||||
|
* Value: | 0 | 0 | 0 0 0 | 0 | 1 1 | = 0x03
|
||||||
|
*/
|
||||||
|
outb(SERIAL_LINE_COMMAND_PORT(com), 0x03);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 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
|
||||||
|
*/
|
||||||
|
void serial_configure_buffers(unsigned short com)
|
||||||
|
{
|
||||||
|
outb(SERIAL_FIFO_COMMAND_PORT(com), 0xc7);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 |
|
||||||
|
void serial_configure_modem(unsigned short com)
|
||||||
|
{
|
||||||
|
outb(SERIAL_MODEM_COMMAND_PORT(com), 0x3);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
*/
|
||||||
|
int serial_is_trasmit_fifo_empty(unsigned short com)
|
||||||
|
{
|
||||||
|
return inb(SERIAL_LINE_STATUS_PORT(com)) & 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serial_write(unsigned short com, char data)
|
||||||
|
{
|
||||||
|
|
||||||
|
while(serial_is_trasmit_fifo_empty(com) == 0); // wait till write finished
|
||||||
|
outb(com, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void serial_print(char *string)
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
while(string[j] != 0)
|
||||||
|
{
|
||||||
|
serial_write(0x3f8, string[j]);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void serial_printf(const char *format, ...) // printf style func for serial port
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
int num; // number to hold our stuff :)
|
||||||
|
char string2[10] = {0}; // string for printing ints :)
|
||||||
|
/* list stuff :) */
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
|
||||||
|
|
||||||
|
while(format[j] != 0)
|
||||||
|
{
|
||||||
|
if(format[j] == '%') // if a format specifier
|
||||||
|
{
|
||||||
|
if(format[j+1] == 'd')
|
||||||
|
{
|
||||||
|
num = va_arg(ap, int);
|
||||||
|
itoa(num, string2);
|
||||||
|
serial_print(string2);
|
||||||
|
zerostring(string2);
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(format[j+1] == 'x')
|
||||||
|
{
|
||||||
|
num = va_arg(ap, int);
|
||||||
|
tohex(num, string2);
|
||||||
|
serial_print(string2);
|
||||||
|
zerostring(string2);
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(format[j+1] == 's')
|
||||||
|
{
|
||||||
|
serial_print(va_arg(ap, char* ));
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
else // unknown format string
|
||||||
|
{
|
||||||
|
serial_print("[ERROR]attempted to parse unknown format string\n");
|
||||||
|
return; // prevent undefined behaviour
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else // is a regular character
|
||||||
|
{
|
||||||
|
serial_write(0x3f8,format[j]);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(ap); // clean up variable length list
|
||||||
|
}
|
||||||
|
|
||||||
|
// init our serial com1 port for debuggin purpoes(rest are general use functions for other ports)
|
||||||
|
#define PORT 0x3f8 /* COM1 */
|
||||||
|
|
||||||
|
void init_serial()
|
||||||
|
{
|
||||||
|
outb(PORT + 1, 0x00); // Disable all interrupts
|
||||||
|
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
||||||
|
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
|
||||||
|
outb(PORT + 1, 0x00); // (hi byte)
|
||||||
|
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||||
|
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||||
|
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||||
|
}
|
39
timer.c
Normal file
39
timer.c
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "headers/timer.h"
|
||||||
|
#include "headers/isr.h"
|
||||||
|
#include "headers/screen.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint32_t tick = 0;
|
||||||
|
extern uint8_t current_color;
|
||||||
|
static void timer_callback(registers_t *regs)
|
||||||
|
{
|
||||||
|
regs->eax++; // get it to compile fix this
|
||||||
|
// later(regs is not really needed)
|
||||||
|
tick++;
|
||||||
|
static int j = 0;
|
||||||
|
j = j%15;
|
||||||
|
current_color = j++;
|
||||||
|
kprintf("%d\n", tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_timer(uint32_t frequency)
|
||||||
|
{
|
||||||
|
// firstly register our timer callback
|
||||||
|
register_interrupt_handler(IRQ0, &timer_callback);
|
||||||
|
|
||||||
|
// the vaue sent to the pit is its clock divisor
|
||||||
|
// (1193180 Hz) the divisor must be small enough
|
||||||
|
// to fit into 16 bits
|
||||||
|
uint32_t divisor = 1193180 / frequency;
|
||||||
|
|
||||||
|
// send the command byte
|
||||||
|
outb(0x43, 0x36);
|
||||||
|
|
||||||
|
// divsor is set in bytes so serialize it
|
||||||
|
uint8_t l = (uint8_t)(divisor & 0xff);
|
||||||
|
uint8_t h = (uint8_t)( (divisor>>8) & 0xff);
|
||||||
|
|
||||||
|
// send the freq divisor
|
||||||
|
outb(0x40, l);
|
||||||
|
outb(0x40, h);
|
||||||
|
}
|
Reference in New Issue
Block a user