Adding error checking and some hints on paging?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
TheGuy
Posts: 13
Joined: Wed Jul 08, 2009 11:14 pm

Adding error checking and some hints on paging?

Post by TheGuy »

Sorry the title is so long.

I want to add error checking to my operating system when its starting up and faults but I cant find to many resources.
I have currently got GDT,IDT,IRQ,IRS,TIMER,KEYBOARD, PAGING and Text Mode.
I am compiling using DJGPP, under Windows Vista SP1.

Important code snippets:

C:\Users\Mike Williams\Desktop\Walls\Milestone 0\July-5-09\src\kernel.h

Code: Select all

#ifndef kernel_h
#define kernel_h

// Some nice typedefs, to standardise sizes across platforms.
// These typedefs are written for 32-bit X86.
typedef unsigned int   u32int;
typedef          int   s32int;
typedef unsigned short u16int;
typedef          short s16int;
typedef unsigned char  u8int;
typedef          char  s8int;

#define COLOR_BLACK     0
#define COLOR_BLUE      1
#define COLOR_GREEN     2
#define COLOR_AQUA      3
#define COLOR_RED       4
#define COLOR_PURPLE    5
#define COLOR_YELLOW    6
#define COLOR_WHITE     7
#define COLOR_GRAY      8
#define COLOR_LTBLUE    9
#define COLOR_LTGREEN   10
#define COLOR_LTAQUA    11
#define COLOR_LTRED     12
#define COLOR_LTPURPLE  13
#define COLOR_LTYELLOW  14
#define COLOR_LTWHITE   15
#define VGA_CRTC_INDEX       0x3D4
#define VGA_CRTC_DATA        0x3D5

#define TRUE  1
#define FALSE 0 


struct regs
{
    unsigned int gs, fs, es, ds;      /* pushed the segs last */
    unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;  /* pushed by 'pusha' */
    unsigned int int_no, err_code;    /* our 'push byte #' and ecodes do this */
    unsigned int eip, cs, eflags, useresp, ss;   /* pushed by the processor automatically */ 
};

typedef struct registers
{
    u32int ds;                  // Data segment selector
    u32int edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha.
    u32int int_no, err_code;    // Interrupt number and error code (if applicable)
    u32int eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.
} registers_t;

/* KERNEL.C */
extern unsigned short *memsetw(unsigned short *dest, unsigned short val, int count);
extern void * memset(void * ptr, int value, int num);
extern void * memcpy(void * destination, const void * source, int num);
extern int strlen(char *str);
extern int strcmp(const char * str1, const char * str2);
extern char * empty(char* str, int size);
extern unsigned char inportb(unsigned short _port);
extern void outportb(unsigned short _port, unsigned char _data);
extern void putsdec(u32int n);
extern void putshex(u32int n);

/* SCREEN.C */
extern void updatecursor();
extern void settextcolor(char fore, char back);
extern void puts(unsigned char *text);
extern void putch(unsigned char c);
extern void cls();
extern void showcursor();
extern void hidecursor();
extern void scroll();
extern void putln();
extern void println(unsigned char *text);
extern void prompt();
extern void backspace();

/* GDT.C */
extern void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran);
extern void gdt_install();

/* IDT.C */
extern void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags);
extern void idt_install();

/* ISRS.C */
extern void isrs_install();

/* IRQ.C */
extern void irq_install();
extern void irq_install_handler(int irq, void (*handler)(struct regs *r));
extern void irq_uninstall_handler(int irq);

/* TIMER.C */
extern void timer_install();
extern void timer_sleep(int sec);

/* KB.C */
extern void keyboard_install();

/* COMMAND.C */
extern void handle_command(char *cmd);

/* KHEAP.C */
extern u32int kmalloc_int(u32int sz, int align, u32int *phys);
extern u32int kmalloc_a(u32int sz);
extern u32int kmalloc_p(u32int sz, u32int *phys);
extern u32int kmalloc_ap(u32int sz, u32int *phys);
extern u32int kmalloc(u32int sz);

/* PAGING.C */
extern void MapFirstTable();
extern unsigned long read_cr0();
extern unsigned long read_cr3();
extern void write_cr0(unsigned long);
extern void write_cr3(unsigned long);

/* PANIC.C */
extern void PANIC(char* information);

#endif
C:\Users\Mike Williams\Desktop\Walls\Milestone 0\July-5-09\src\paging.h

Code: Select all

// Includes
#include "kernel.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Page direcory 'Just need some free memory (4kb) that is aligned (can be divided by: 4096 without a remainder).' 0x9C000
unsigned long *page_directory = (unsigned long *) 0x9C000;

// Page Table the page table comes right after the page directory
unsigned long *page_table = (unsigned long *) 0x9D000;

// Address holds the physical address of where a page is
unsigned long address=0; 

// I is a basic counting variable for our loops
unsigned int i;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Maps the first table, then sets up other basic requirements
void MapFirstTable()
{

// Map the first 4MB of memory
for(i=0; i<1024; i++)
{
	page_table[i] = address | 3; // attribute set to: supervisor level, read/write, present(011 in binary)
	address = address + 4096; // 4096 = 4kb
};


// fill the first entry of the page directory
page_directory[0] = page_table; // attribute set to: supervisor level, read/write, present(011 in binary)
page_directory[0] = page_directory[0] | 3;

for(i=1; i<1024; i++)
{
	page_directory[i] = 0 | 2; // attribute set to: supervisor level, read/write, not present(010 in binary)
};

// write_cr3, read_cr3, write_cr0, and read_cr0 all come from the assembly functions
write_cr3(page_directory); // put that page directory address into CR3
write_cr0((unsigned long)read_cr0() | 0x80000000); // set the paging bit in CR0 to 1

// PAGING IS ENABLED
}
C:\Users\Mike Williams\Desktop\Walls\Milestone 0\July-5-09\src\boot.asm

Code: Select all

[BITS 32]
global _start, _multiboot, _halt, _kernel_stack
extern _kernel, _linkt, _linkd, _linkb

MULTIBOOT_PAGE_ALIGN     equ 1<<0
MULTIBOOT_AOUT_KLUDGE    equ 1<<16
MULTIBOOT_HEADER_MAGIC   equ 0x1BADB002
MULTIBOOT_HEADER_FLAGS   equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_AOUT_KLUDGE
MULTIBOOT_CHECKSUM       equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

_start:
       jmp short _startup
       align 4
_multiboot:
        dd MULTIBOOT_HEADER_MAGIC
        dd MULTIBOOT_HEADER_FLAGS
        dd MULTIBOOT_CHECKSUM
        dd _multiboot
        dd _linkt
        dd _linkd
        dd _linkb
        dd _start
_startup:
    extern _kernel
    call _kernel
    jmp $

; This will set up our new segment registers. We need to do
; something special in order to set CS. We do what is called a
; far jump. A jump that includes a segment as well as an offset.
; This is declared in C as 'extern void gdt_flush();'
global _gdt_flush
extern _gp
_gdt_flush:
    lgdt [_gp]
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:flush2
flush2:
    ret

; Loads the IDT defined in '_idtp' into the processor.
; This is declared in C as 'extern void idt_load();'
global _idt_load
extern _idtp
_idt_load:
    lidt [_idtp]
    ret

; In just a few pages in this tutorial, we will add our Interrupt
; Service Routines (ISRs) right here!
global _isr0
global _isr1
global _isr2
global _isr3
global _isr4
global _isr5
global _isr6
global _isr7
global _isr8
global _isr9
global _isr10
global _isr11
global _isr12
global _isr13
global _isr14
global _isr15
global _isr16
global _isr17
global _isr18
global _isr19
global _isr20
global _isr21
global _isr22
global _isr23
global _isr24
global _isr25
global _isr26
global _isr27
global _isr28
global _isr29
global _isr30
global _isr31

;  0: Divide By Zero Exception
_isr0:
    cli
    push byte 0
    push byte 0
    jmp isr_common_stub

;  1: Debug Exception
_isr1:
    cli
    push byte 0
    push byte 1
    jmp isr_common_stub

;  2: Non Maskable Interrupt Exception
_isr2:
    cli
    push byte 0
    push byte 2
    jmp isr_common_stub

;  3: Int 3 Exception
_isr3:
    cli
    push byte 0
    push byte 3
    jmp isr_common_stub

;  4: INTO Exception
_isr4:
    cli
    push byte 0
    push byte 4
    jmp isr_common_stub

;  5: Out of Bounds Exception
_isr5:
    cli
    push byte 0
    push byte 5
    jmp isr_common_stub

;  6: Invalid Opcode Exception
_isr6:
    cli
    push byte 0
    push byte 6
    jmp isr_common_stub

;  7: Coprocessor Not Available Exception
_isr7:
    cli
    push byte 0
    push byte 7
    jmp isr_common_stub

;  8: Double Fault Exception (With Error Code!)
_isr8:
    cli
    push byte 8
    jmp isr_common_stub

;  9: Coprocessor Segment Overrun Exception
_isr9:
    cli
    push byte 0
    push byte 9
    jmp isr_common_stub

; 10: Bad TSS Exception (With Error Code!)
_isr10:
    cli
    push byte 10
    jmp isr_common_stub

; 11: Segment Not Present Exception (With Error Code!)
_isr11:
    cli
    push byte 11
    jmp isr_common_stub

; 12: Stack Fault Exception (With Error Code!)
_isr12:

    cli
    push byte 12
    jmp isr_common_stub

; 13: General Protection Fault Exception (With Error Code!)
_isr13:
    cli
    push byte 13
    jmp isr_common_stub

; 14: Page Fault Exception (With Error Code!)
_isr14:
    cli
    push byte 14
    jmp isr_common_stub

; 15: Reserved Exception
_isr15:
    cli
    push byte 0
    push byte 15
    jmp isr_common_stub

; 16: Floating Point Exception
_isr16:
    cli
    push byte 0
    push byte 16
    jmp isr_common_stub

; 17: Alignment Check Exception
_isr17:
    cli
    push byte 0
    push byte 17
    jmp isr_common_stub

; 18: Machine Check Exception
_isr18:
    cli
    push byte 0
    push byte 18
    jmp isr_common_stub

; 19: Reserved
_isr19:
    cli
    push byte 0
    push byte 19
    jmp isr_common_stub

; 20: Reserved
_isr20:
    cli
    push byte 0
    push byte 20
    jmp isr_common_stub

; 21: Reserved
_isr21:
    cli
    push byte 0
    push byte 21
    jmp isr_common_stub

; 22: Reserved
_isr22:
    cli
    push byte 0
    push byte 22
    jmp isr_common_stub

; 23: Reserved
_isr23:
    cli
    push byte 0
    push byte 23
    jmp isr_common_stub

; 24: Reserved
_isr24:
    cli
    push byte 0
    push byte 24
    jmp isr_common_stub

; 25: Reserved
_isr25:
    cli
    push byte 0
    push byte 25
    jmp isr_common_stub

; 26: Reserved
_isr26:
    cli
    push byte 0
    push byte 26
    jmp isr_common_stub

; 27: Reserved
_isr27:
    cli
    push byte 0
    push byte 27
    jmp isr_common_stub

; 28: Reserved
_isr28:
    cli
    push byte 0
    push byte 28
    jmp isr_common_stub

; 29: Reserved
_isr29:
    cli
    push byte 0
    push byte 29
    jmp isr_common_stub

; 30: Reserved
_isr30:
    cli
    push byte 0
    push byte 30
    jmp isr_common_stub

; 31: Reserved
_isr31:
    cli
    push byte 0
    push byte 31
    jmp isr_common_stub


; We call a C function in here. We need to let the assembler know
; that '_fault_handler' exists in another file
extern _fault_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
    push ds
    push es
    push fs
    push gs
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp
    push eax
    mov eax, _fault_handler
    call eax
    pop eax
    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

global _irq0
global _irq1
global _irq2
global _irq3
global _irq4
global _irq5
global _irq6
global _irq7
global _irq8
global _irq9
global _irq10
global _irq11
global _irq12
global _irq13
global _irq14
global _irq15

; 32: IRQ0
_irq0:
    cli
    push byte 0
    push byte 32
    jmp irq_common_stub

; 33: IRQ1
_irq1:
    cli
    push byte 0
    push byte 33
    jmp irq_common_stub

; 34: IRQ2
_irq2:
    cli
    push byte 0
    push byte 34
    jmp irq_common_stub

; 35: IRQ3
_irq3:
    cli
    push byte 0
    push byte 35
    jmp irq_common_stub

; 36: IRQ4
_irq4:
    cli
    push byte 0
    push byte 36
    jmp irq_common_stub

; 37: IRQ5
_irq5:
    cli
    push byte 0
    push byte 37
    jmp irq_common_stub

; 38: IRQ6
_irq6:
    cli
    push byte 0
    push byte 38
    jmp irq_common_stub

; 39: IRQ7
_irq7:
    cli
    push byte 0
    push byte 39
    jmp irq_common_stub

; 40: IRQ8
_irq8:
    cli
    push byte 0
    push byte 40
    jmp irq_common_stub

; 41: IRQ9
_irq9:
    cli
    push byte 0
    push byte 41
    jmp irq_common_stub

; 42: IRQ10
_irq10:
    cli
    push byte 0
    push byte 42
    jmp irq_common_stub

; 43: IRQ11
_irq11:
    cli
    push byte 0
    push byte 43
    jmp irq_common_stub

; 44: IRQ12
_irq12:
    cli
    push byte 0
    push byte 44
    jmp irq_common_stub

; 45: IRQ13
_irq13:
    cli
    push byte 0
    push byte 45
    jmp irq_common_stub

; 46: IRQ14
_irq14:
    cli
    push byte 0
    push byte 46
    jmp irq_common_stub

; 47: IRQ15
_irq15:
    cli
    push byte 0
    push byte 47
    jmp irq_common_stub

extern _irq_handler

irq_common_stub:
    pusha
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp

    push eax
    mov eax, _irq_handler
    call eax
    pop eax

    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

; Read + Write functions for CR0 / CR3 registers
; Self explainitory
[global _read_cr0]
_read_cr0:
	mov eax, cr0
	retn

[global _write_cr0]
_write_cr0:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr0,  eax
	pop ebp
	retn

[global _read_cr3]
_read_cr3:
	mov eax, cr3
	retn

[global _write_cr3]
_write_cr3:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr3, eax
	pop ebp
	retn


; Here is the definition of our BSS section. Right now, we'll use
; it just to store the stack. Remember that a stack actually grows
; downwards, so we declare the size of the data before declaring
; the identifier '_sys_stack'
SECTION .bss
    resb 8192               ; This reserves 8KBytes of memory here
_sys_stack:

Thanks in advanced.

~Mike
User avatar
salil_bhagurkar
Member
Member
Posts: 261
Joined: Mon Feb 19, 2007 10:40 am
Location: India

Re: Adding error checking and some hints on paging?

Post by salil_bhagurkar »

You already have implemented exception handling. Apart from that, I think you cannot do anything more than checking for the processor version (386, 486 etc). If some part of your code does not support a version then you can do error checking based on that. The code above, is basically meant to work in all respects, since there is no user-selected part in it at runtime. If it does not work then there is no point booting your OS anyway.
TheGuy
Posts: 13
Joined: Wed Jul 08, 2009 11:14 pm

Re: Adding error checking and some hints on paging?

Post by TheGuy »

salil_bhagurkar wrote:You already have implemented exception handling. Apart from that, I think you cannot do anything more than checking for the processor version (386, 486 etc). If some part of your code does not support a version then you can do error checking based on that. The code above, is basically meant to work in all respects, since there is no user-selected part in it at runtime. If it does not work then there is no point booting your OS anyway.
Ok thank you. I will look into CPUID for Intel and AMD.
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Re: Adding error checking and some hints on paging?

Post by frank »

You might want to add some code to make sure the memory map returned by GRUB is safe to use and that the computer has enough memory. You wouldn't want the OS to fail in some weird way because you tried to build a page directory in non-existent memory.
Post Reply