Okay,
First, regarding the style, I agree but for me this is just a sand box that I use to understand well and then start writing the whole thing in a more elegant way, so forgive me for that.
i.e. I am in the phase now of lighting up all the dark rooms before decorating them
Now, for Bochs I don't get the page fault that I get in qemu. It works like a charm!
Attached is a screenshot for the same code running on Bochs
Regarding the mapping of my interrupt routines, here is the code that I use
Code: Select all
void idtStart(void) {
/* Set IDT Pointer */
idtP.limit = (sizeof(idtEntry) * IDT_SIZE) - 1;
idtP.base = (uint64_t)&idt;
/* Clear Memory for IDT's */
memset((uint8_t *)&idt, 0, sizeof(idtEntry) * IDT_SIZE);
memset((uint8_t *)&interrupt_handlers, 0, sizeof(isr_t)*256);
Ports::outportb(0x20, 0x11);
Ports::outportb(0xA0, 0x11);
Ports::outportb(0x21, 0x20);
Ports::outportb(0xA1, 0x28);
Ports::outportb(0x21, 0x04);
Ports::outportb(0xA1, 0x02);
Ports::outportb(0x21, 0x01);
Ports::outportb(0xA1, 0x01);
Ports::outportb(0x21, 0x0);
Ports::outportb(0xA1, 0x0);
/* Set IDT Gates */
idtSet(0, (uint64_t)isr0, 0x08, 0x8E);
idtSet(1, (uint64_t)isr1, 0x08, 0x8E);
idtSet(2, (uint64_t)isr2, 0x08, 0x8E);
idtSet(3, (uint64_t)isr3, 0x08, 0x8E);
idtSet(4, (uint64_t)isr4, 0x08, 0x8E);
idtSet(5, (uint64_t)isr5, 0x08, 0x8E);
idtSet(6, (uint64_t)isr6, 0x08, 0x8E);
idtSet(7, (uint64_t)isr7, 0x08, 0x8E);
idtSet(8, (uint64_t)isr8, 0x08, 0x8E);
idtSet(9, (uint64_t)isr9, 0x08, 0x8E);
idtSet(10, (uint64_t)isr10, 0x08, 0x8E);
idtSet(11, (uint64_t)isr11, 0x08, 0x8E);
idtSet(12, (uint64_t)isr12, 0x08, 0x8E);
idtSet(13, (uint64_t)isr13, 0x08, 0x8E);
idtSet(14, (uint64_t)isr14, 0x08, 0x8E);
idtSet(15, (uint64_t)isr15, 0x08, 0x8E);
idtSet(16, (uint64_t)isr16, 0x08, 0x8E);
idtSet(17, (uint64_t)isr17, 0x08, 0x8E);
idtSet(18, (uint64_t)isr18, 0x08, 0x8E);
idtSet(19, (uint64_t)isr19, 0x08, 0x8E);
idtSet(20, (uint64_t)isr20, 0x08, 0x8E);
idtSet(21, (uint64_t)isr21, 0x08, 0x8E);
idtSet(22, (uint64_t)isr22, 0x08, 0x8E);
idtSet(23, (uint64_t)isr23, 0x08, 0x8E);
idtSet(24, (uint64_t)isr24, 0x08, 0x8E);
idtSet(25, (uint64_t)isr25, 0x08, 0x8E);
idtSet(26, (uint64_t)isr26, 0x08, 0x8E);
idtSet(27, (uint64_t)isr27, 0x08, 0x8E);
idtSet(28, (uint64_t)isr28, 0x08, 0x8E);
idtSet(29, (uint64_t)isr29, 0x08, 0x8E);
idtSet(30, (uint64_t)isr30, 0x08, 0x8E);
idtSet(31, (uint64_t)isr31, 0x08, 0x8E);
idtSet(32, (uint64_t)irq0, 0x08, 0x8E);
idtSet(33, (uint64_t)irq1, 0x08, 0x8E);
idtSet(34, (uint64_t)irq2, 0x08, 0x8E);
idtSet(35, (uint64_t)irq3, 0x08, 0x8E);
idtSet(36, (uint64_t)irq4, 0x08, 0x8E);
idtSet(37, (uint64_t)irq5, 0x08, 0x8E);
idtSet(38, (uint64_t)irq6, 0x08, 0x8E);
idtSet(39, (uint64_t)irq7, 0x08, 0x8E);
idtSet(40, (uint64_t)irq8, 0x08, 0x8E);
idtSet(41, (uint64_t)irq9, 0x08, 0x8E);
idtSet(42, (uint64_t)irq10, 0x08, 0x8E);
idtSet(43, (uint64_t)irq11, 0x08, 0x8E);
idtSet(44, (uint64_t)irq12, 0x08, 0x8E);
idtSet(45, (uint64_t)irq13, 0x08, 0x8E);
idtSet(46, (uint64_t)irq14, 0x08, 0x8E);
idtSet(47, (uint64_t)irq15, 0x08, 0x8E);
/* Load IDT Table */
idtInit();
}
The ports operation I have encapsulated them in a class:
Code: Select all
#ifndef PORTS_H_
#define PORTS_H_
#include "defines.h"
#include "includes.h"
class Ports
{
private:
public:
static void outportb (unsigned short port,unsigned char data);
static unsigned char inportb( unsigned short port);
static unsigned short inportw( unsigned short port);
};
#endif /* PORTS_H_ */
Code: Select all
#include "Ports.h"
void Ports::outportb (unsigned short port,unsigned char data)
{
asm volatile ("outb %1, %0" : : "dN" (port), "a" (data));
}
unsigned char Ports::inportb( unsigned short port)
{
unsigned char ret;
asm volatile("inb %1, %0" : "=a" (ret) : "dN" (port));
return ret;
}
unsigned short Ports::inportw( unsigned short port)
{
unsigned short ret;
asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port));
return ret;
}
My IRQ Assembly code is here:
Code: Select all
[BITS 64]
%macro pushAll 0
push rax
push rbx
push rcx
push rdx
push rbp
push rsi
push rdi
push rsp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
%endmacro
%macro popAll 0
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rsp
pop rdi
pop rsi
pop rbp
pop rdx
pop rcx
pop rbx
pop rax
%endmacro
global idtInit
extern idtP
idtInit:
lidt [idtP]
ret
;/*
; * Interrupt Handler
; */
extern isrHandler
isrCommon:
pushAll
mov ax, ds
push rax
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call isrHandler
pop rbx
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popAll
add rsp,16
sti
iretq
extern irq_handler
; This is 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:
pushAll ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Lower 16-bits of eax = ds.
push rax ; 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
call irq_handler
pop rbx ; reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popAll ; Pops edi,esi,ebp..
add rsp, 16 ; Cleans up the pushed error code and pushed ISR number
sti
iretq ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
%macro ISR_NOERRCODE 1
[GLOBAL isr%1]
isr%1:
cli
push byte 0
push byte %1
jmp isrCommon
%endmacro
%macro ISR_ERRCODE 1
[GLOBAL isr%1]
isr%1:
cli
push byte %1
jmp isrCommon
%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_NOERRCODE 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_NOERRCODE 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
And finally my GDT declaration is here:
Code: Select all
GDT64: ; Global Descriptor Table (64-bit).
.Null: equ $ - GDT64 ; The null descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 0 ; Access.
db 0 ; Granularity.
db 0 ; Base (high).
.Code: equ $ - GDT64 ; The code descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10011000b ; Access.
db 00100000b ; Granularity.
db 0 ; Base (high).
.Data: equ $ - GDT64 ; The data descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10010000b ; Access.
db 00000000b ; Granularity.
db 0 ; Base (high).
.Pointer: ; The GDT-pointer.
dw $ - GDT64 - 1 ; Limit.
dq GDT64 ; Base.
Regarding the CR0.PG, I do that in a seperate routine that is call immediatly after EnablePaging, and here is the code for it:
Code: Select all
FromProtected:
pushf
push ds
push es
push di
push si
mov ecx, 0xC0000080 ; Set the C-register to 0xC0000080, which is the EFER MSR.
rdmsr ; Read from the model-specific register.
or eax, 1 << 8 ; Set the LM-bit which is the 9th bit (bit 8).
wrmsr ; Write to the model-specific register.
mov eax, cr0 ; Set the A-register to control register 0.
or eax,1 << 31 ; Set the PG-bit, which is the 32nd bit (bit 31).
mov cr0, eax ; Set control register 0 to the A-register.
pop si
pop di
pop es
pop ds
popf
ret
Thanks,
Karim.