Re: General Protection Fault upon return from Intterupt hand
Posted: Thu Mar 27, 2014 3:36 pm
Dear Sortie,
Thanks a lot for your thorough reply, although I did not get from it except that I need to clean my code.
This code I am experimenting with so I can learn more about kernels and get more in depth knowledge, so what I have is a sandbox that I am trying things out with, and one day when I am confident enought I might sit down and write a cleaner kernel; so it is not meant to be as clean as you expect.
Nevertheless, I agree that the code was not clean, but as you said I was following the tutorial by James Molloy trying to learn, and I did not have a clue that there is a complete page with bugs/problems regarding the tutroial, and I would like to thank you for refering to that; I totally missed the link even though it is just to the right of the tutorial link.
I just have one comment regarding the atitude and the language being used in communication, kindly I would prefer that generally people choose their language and select appropriate words when trying to transfer knowledge to others. Words that starts with "F" and using stupid a lot, I don't think it is very appropriate in general, at the end of the day I think that people hangout here on this forum to share information and to help each other rather than enumerating problems without really much of a help; you should consider that you are describing stuff to a range of people who are not all at the same level of understanding of the topic and that is why they are seeking help in the first place; so explaining to someone a subject as if he already understand is totally defeating the purpose. You might be storng in a specific area but this really does not matter for people like me, what really matters is the quality of the help. At the end of the day I think that James Molloy did a lot of people like me a favour by spending some of his time providing people like me such tutorial which at least introduced a lot to me even though it has some bugs (like any piece of software), so I think it is not fair using the word "stupid" in that context, rather I would expect you to show us your elegant code and do the intiative of updating the tutorial, correcting it, and providing V2 of it.
Now back to the tech stuff, regarding the problem I have, I followed your reply as much as I can and I sat down for the past three hours trying to clean the code as much as possible; At the end of my post you will find two code sections with the newer version after cleaning it. (The Full code is the code for the First Experiment: read below and you will understand)
Obvioiusly there is something wrong with my understanding of the interrupt handler code, so I did three experiments.
The first experiment, I removed completely all the parameters to my interrupt handler and all what it does is to print a hello world message with a counter to ensure that it is being fired contineously, it is not even aware of the interrupt number and all what I aimed at is to make it return without crashing the VM. Here is the code of my interrupt related code for that experiment, and it worked fine. One thing to mention here is as you can see I had to add 16 to the rsp and not 8, and it did not work with 8 (VM crashes), so it would be good if you have an explanation for that because I don't.
In the second experiment, I aimed at passing the interrupt number and the error code originally pushed on the stack in the isr and irq macros. I did that by passing them by value, and to do that without messing up with the ds register being pushed on the stack I had to move the pushing of the ds into the macros to take place before pushing the interrupt number and the error code, and this worked and displayed the interrupt number of PIC "32" on the screen, and I also added a counter to make sure that it is being fired contineously.One thing I would like to mention is the parameters to the interrupt handler which are two uint64_t and not uint8_t. Below is the code.
In the third experiment, I created a new structure for the interrupt number and the error code and tried to pass it by reference as per the code below and I could not make it work (VM Crashes)
I also attached 2 screen shots for the first two experiments
Finally I have a couple of questions regarding your post
First what did you mean by the following:
I googled a lot trying to find the bits definition of the IDT flag to set the cli/sti per interrupt but I could not find it, so can you please send me any reference for that?
Thanks a lot for your thorough reply, although I did not get from it except that I need to clean my code.
This code I am experimenting with so I can learn more about kernels and get more in depth knowledge, so what I have is a sandbox that I am trying things out with, and one day when I am confident enought I might sit down and write a cleaner kernel; so it is not meant to be as clean as you expect.
Nevertheless, I agree that the code was not clean, but as you said I was following the tutorial by James Molloy trying to learn, and I did not have a clue that there is a complete page with bugs/problems regarding the tutroial, and I would like to thank you for refering to that; I totally missed the link even though it is just to the right of the tutorial link.
I just have one comment regarding the atitude and the language being used in communication, kindly I would prefer that generally people choose their language and select appropriate words when trying to transfer knowledge to others. Words that starts with "F" and using stupid a lot, I don't think it is very appropriate in general, at the end of the day I think that people hangout here on this forum to share information and to help each other rather than enumerating problems without really much of a help; you should consider that you are describing stuff to a range of people who are not all at the same level of understanding of the topic and that is why they are seeking help in the first place; so explaining to someone a subject as if he already understand is totally defeating the purpose. You might be storng in a specific area but this really does not matter for people like me, what really matters is the quality of the help. At the end of the day I think that James Molloy did a lot of people like me a favour by spending some of his time providing people like me such tutorial which at least introduced a lot to me even though it has some bugs (like any piece of software), so I think it is not fair using the word "stupid" in that context, rather I would expect you to show us your elegant code and do the intiative of updating the tutorial, correcting it, and providing V2 of it.
Now back to the tech stuff, regarding the problem I have, I followed your reply as much as I can and I sat down for the past three hours trying to clean the code as much as possible; At the end of my post you will find two code sections with the newer version after cleaning it. (The Full code is the code for the First Experiment: read below and you will understand)
Obvioiusly there is something wrong with my understanding of the interrupt handler code, so I did three experiments.
The first experiment, I removed completely all the parameters to my interrupt handler and all what it does is to print a hello world message with a counter to ensure that it is being fired contineously, it is not even aware of the interrupt number and all what I aimed at is to make it return without crashing the VM. Here is the code of my interrupt related code for that experiment, and it worked fine. One thing to mention here is as you can see I had to add 16 to the rsp and not 8, and it did not work with 8 (VM crashes), so it would be good if you have an explanation for that because I don't.
Code: Select all
extern "C" void idt_handler()
{
tick++;
video.setPosition(10,10);
video.putString("Hello World: ",COLOR_BLUE,COLOR_WHITE);
video.putDecimal(tick,COLOR_BLUE,COLOR_WHITE);
video.putString(" ",COLOR_BLUE,COLOR_WHITE);
Ports::outportb(PIC1_COMMAND, 0x20);
}
idt_common_stub:
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 idt_handler
pop rbx ; reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
add rsp,16
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 idt_common_stub
%endmacro
%macro ISR_ERRCODE 1
[GLOBAL isr%1]
isr%1:
cli
push byte %1
jmp idt_common_stub
%endmacro
%macro IRQ 2
global irq%1
irq%1:
cli
push byte 0
push byte %2
jmp idt_common_stub
%endmacro
In the second experiment, I aimed at passing the interrupt number and the error code originally pushed on the stack in the isr and irq macros. I did that by passing them by value, and to do that without messing up with the ds register being pushed on the stack I had to move the pushing of the ds into the macros to take place before pushing the interrupt number and the error code, and this worked and displayed the interrupt number of PIC "32" on the screen, and I also added a counter to make sure that it is being fired contineously.One thing I would like to mention is the parameters to the interrupt handler which are two uint64_t and not uint8_t. Below is the code.
Code: Select all
extern "C" void idt_handler(uint64_t v1,uint64_t v2)
{
tick++;
video.setPosition(10,10);
video.putString("interupt: ",COLOR_BLUE,COLOR_WHITE);
video.putDecimal(v1,COLOR_BLUE,COLOR_WHITE);
video.putString(", Counter: ",COLOR_BLUE,COLOR_WHITE);
video.putDecimal(tick,COLOR_BLUE,COLOR_WHITE);
video.putString(" ",COLOR_BLUE,COLOR_WHITE);
// Send an EOI (end of interrupt) signal to the PICs.
// If this interrupt involved the slave.
if (v1 >= 40)
{
// Send reset signal to slave.
Ports::outportb(PIC2_COMMAND, 0x20);
}
// Send reset signal to master. (As well as slave, if necessary).
Ports::outportb(PIC1_COMMAND, 0x20);
}
idt_common_stub:
mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call idt_handler
pop rbx ; reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
add rsp,16
iretq ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
%macro ISR_NOERRCODE 1
[GLOBAL isr%1]
isr%1:
cli
mov ax, ds ; Lower 16-bits of eax = ds.
push rax ; save the data segment descriptor
push byte 0
push byte %1
jmp idt_common_stub
%endmacro
%macro ISR_ERRCODE 1
[GLOBAL isr%1]
isr%1:
cli
mov ax, ds ; Lower 16-bits of eax = ds.
push rax ; save the data segment descriptor
push byte %1
jmp idt_common_stub
%endmacro
%macro IRQ 2
global irq%1
irq%1:
cli
mov ax, ds ; Lower 16-bits of eax = ds.
push rax ; save the data segment descriptor
push byte 0
push byte %2
jmp idt_common_stub
%endmacro
Code: Select all
struct interrupts{
uint64_t intNo, errCode;
} ;
extern "C" void idt_handler(struct interrupts * _interrupts)
{
tick++;
video.setPosition(10,10);
video.putString("interupt: ",COLOR_BLUE,COLOR_WHITE);
video.putDecimal(_interrupts->intNo,COLOR_BLUE,COLOR_WHITE);
video.putString(", Counter: ",COLOR_BLUE,COLOR_WHITE);
video.putDecimal(tick,COLOR_BLUE,COLOR_WHITE);
video.putString(" ",COLOR_BLUE,COLOR_WHITE);
// Send an EOI (end of interrupt) signal to the PICs.
// If this interrupt involved the slave.
if (_interrupts->intNo >= 40)
{
// Send reset signal to slave.
Ports::outportb(PIC2_COMMAND, 0x20);
}
// Send reset signal to master. (As well as slave, if necessary).
Ports::outportb(PIC1_COMMAND, 0x20);
}
; This is our common stub for both irqs and isrs
idt_common_stub:
mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push rsp
call idt_handler
pop rbx ; reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
add rsp,16
iretq ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
%macro ISR_NOERRCODE 1
[GLOBAL isr%1]
isr%1:
cli
mov ax, ds ; Lower 16-bits of eax = ds.
push rax ; save the data segment descriptor
push byte 0
push byte %1
jmp idt_common_stub
%endmacro
%macro ISR_ERRCODE 1
[GLOBAL isr%1]
isr%1:
cli
mov ax, ds ; Lower 16-bits of eax = ds.
push rax ; save the data segment descriptor
push byte %1
jmp idt_common_stub
%endmacro
%macro IRQ 2
global irq%1
irq%1:
cli
mov ax, ds ; Lower 16-bits of eax = ds.
push rax ; save the data segment descriptor
push byte 0
push byte %2
jmp idt_common_stub
%endmacro
I also attached 2 screen shots for the first two experiments
Finally I have a couple of questions regarding your post
First what did you mean by the following:
You are pushing the general purpose registers onto the kernel stack before you have changed the the data segment. You don't need to change the stack segment, since the CPU does that for you. I forgot if any of this is even needed on x86_64.
I googled a lot trying to find the bits definition of the IDT flag to set the cli/sti per interrupt but I could not find it, so can you please send me any reference for that?
You clear interrupts when you enter the interrupt handler, but as described in my above link, that's stupid and you should just decide whether you want interrupts on when you set the IDT entries.
Code: Select all
[BITS 64]
global idtInit
extern idtP
idtInit:
lidt [idtP]
iretq
extern idt_handler
; This is our common stub for both irqs and isrs
idt_common_stub:
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 idt_handler
pop rbx ; reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
add rsp,16
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 idt_common_stub
%endmacro
%macro ISR_ERRCODE 1
[GLOBAL isr%1]
isr%1:
cli
push byte %1
jmp idt_common_stub
%endmacro
%macro IRQ 2
global irq%1
irq%1:
cli
push byte 0
push byte %2
jmp idt_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
Code: Select all
#include "icxxabi.h"
#include "Video.h"
#include "Disk.h"
#include "CPUID.h"
#include "PageManager.h"
#include "MemoryManager.h"
#include "HeapIndexItem.h"
#include "PCIConfigHeaderManager.h"
#include "new.h"
#include "E1000.h"
#include "rtl8139.h"
/*
* Interrupt Descriptor Structure
*/
#define IDT_SIZE 256
#define MAIN_FILE
#include "globals.h"
const char * exception_messages[32] =
{
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint Exception",
"Into Detected Overflow Exception",
"Out of Bounds Exception",
"Invalid Opcode Exception",
"No Coprocessor Exception",
"Double Fault Exception",
"Coprocessor Segment Overrun Exception",
"Bad TSS Exception",
"Segment Not Present Exception",
"Stack Fault Exception",
"General Protection Fault Exception",
"Page Fault Exception",
"Unknown Interrupt Exception",
"Coprocessor Fault Exception",
"Alignment Check Exception (486+)",
"Machine Check Exception (Pentium/586+)",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions",
"Reserved Exceptions"
};
char kbdus[128] =
{
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */
'9', '0', '-', '=', '\b', /* Backspace */
'\t', /* Tab */
'q', 'w', 'e', 'r', /* 19 */
't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */
0, /* 29 - Control */
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */
'\'', '`', 0, /* Left shift */
'\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */
'm', ',', '.', '/', 0, /* Right shift */
'*',
0, /* Alt */
' ', /* Space bar */
0, /* Caps lock */
0, /* 59 - F1 key ... > */
0, 0, 0, 0, 0, 0, 0, 0,
0, /* < ... F10 */
0, /* 69 - Num lock*/
0, /* Scroll Lock */
0, /* Home key */
0, /* Up Arrow */
0, /* Page Up */
'-',
0, /* Left Arrow */
0,
0, /* Right Arrow */
'+',
0, /* 79 - End key*/
0, /* Down Arrow */
0, /* Page Down */
0, /* Insert Key */
0, /* Delete Key */
0, 0, 0,
0, /* F11 Key */
0, /* F12 Key */
0, /* All other keys are undefined */
};
/*
* Prototypes
*/
void idtStart(void);
void idtSet(uint8_t, uint64_t, uint16_t, uint8_t);
extern "C" void isrHandler(struct registers *);
extern "C" void idtInit();
extern "C" void isr0();
extern "C" void isr1();
extern "C" void isr2();
extern "C" void isr3();
extern "C" void isr4();
extern "C" void isr5();
extern "C" void isr6();
extern "C" void isr7();
extern "C" void isr8();
extern "C" void isr9();
extern "C" void isr10();
extern "C" void isr11();
extern "C" void isr12();
extern "C" void isr13();
extern "C" void isr14();
extern "C" void isr15();
extern "C" void isr16();
extern "C" void isr17();
extern "C" void isr18();
extern "C" void isr19();
extern "C" void isr20();
extern "C" void isr21();
extern "C" void isr22();
extern "C" void isr23();
extern "C" void isr24();
extern "C" void isr25();
extern "C" void isr26();
extern "C" void isr27();
extern "C" void isr28();
extern "C" void isr29();
extern "C" void isr30();
extern "C" void isr31();
extern "C" void irq0 ();
extern "C" void irq1 ();
extern "C" void irq2 ();
extern "C" void irq3 ();
extern "C" void irq4 ();
extern "C" void irq5 ();
extern "C" void irq6 ();
extern "C" void irq7 ();
extern "C" void irq8 ();
extern "C" void irq9 ();
extern "C" void irq10();
extern "C" void irq11();
extern "C" void irq12();
extern "C" void irq13();
extern "C" void irq14();
extern "C" void irq15();
/* Setup Table and Pointer */
idtEntry idt[IDT_SIZE];
idtPointer idtP;
void IRQ_set_mask(unsigned char IRQline) {
uint16_t port;
uint8_t value;
if(IRQline < 8) {
port = PIC1_DATA;
} else {
port = PIC2_DATA;
IRQline -= 8;
}
value = Ports::inportb(port) | (1 << IRQline);
Ports::outportb(port, value);
}
void IRQ_clear_mask(unsigned char IRQline) {
uint16_t port;
uint8_t value;
if(IRQline < 8) {
port = PIC1_DATA;
} else {
port = PIC2_DATA;
IRQline -= 8;
}
value = Ports::inportb(port) & ~(1 << IRQline);
Ports::outportb(port, value);
}
void register_interrupt_handler(uint8_t n, isr_t handler)
{
interrupt_handlers[n] = handler;
if ( n >= IRQ0)
IRQ_clear_mask(n-IRQ0);
}
void idtStart(void) {
/* Set IDT Pointer */
idtP.limit = (sizeof(idtEntry) * IDT_SIZE) - 1;
idtP.base = (uint64_t)&idt;
/* Clear Memory for IDT's */
Utils::memset((uint8_t *)&idt, 0, sizeof(idtEntry) * IDT_SIZE);
Utils::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);
for ( unsigned char c = 0 ; c < 16 ; c++)
IRQ_set_mask(c);
/* 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();
}
void idtSet(uint8_t number, uint64_t base, uint16_t selector, uint8_t flags) {
/* Set Base Address */
idt[number].baseLow = base & 0xFFFF;
idt[number].baseMid = (base >> 16) & 0xFFFF;
idt[number].baseHigh = (base >> 32) & 0xFFFFFFFF;
/* Set Selector */
idt[number].selector = selector;
idt[number].flags = flags;
/* Set Reserved Areas to Zero */
idt[number].reservedIst = 0;
idt[number].reserved = 0;
}
extern "C" void idt_handler()
{
tick++;
video.setPosition(10,10);
video.putString("Hello World: ",COLOR_BLUE,COLOR_WHITE);
video.putDecimal(tick,COLOR_BLUE,COLOR_WHITE);
video.putString(" ",COLOR_BLUE,COLOR_WHITE);
Ports::outportb(PIC1_COMMAND, 0x20);
}
static void timer_callback()
{
tick++;
video.setPosition(50,12);
video.putString("Tick: ",COLOR_BLUE,COLOR_WHITE);
video.putDecimal(tick,COLOR_BLUE,COLOR_WHITE);
video.putString("\n",COLOR_BLUE,COLOR_WHITE);
}
static void keyboard_callback()
{
unsigned char status = Ports::inportb(0x64);
unsigned char sc = Ports::inportb(0x60);
if ( sc&0x80)
{
}
else
{
video.setPosition(40,15);
char mychar = kbdus[sc];
video.putString("Got Character: ",COLOR_BLUE,COLOR_WHITE);
video.putCharacter((char)mychar,COLOR_BLUE,COLOR_WHITE);
video.putString("\n",COLOR_BLUE,COLOR_WHITE);
}
}
void init_timer(uint32_t frequency)
{
// Firstly, register our timer callback.
register_interrupt_handler(IRQ0, &timer_callback);
register_interrupt_handler(IRQ1, &keyboard_callback);
// The value we send to the PIT is the value to divide it's input clock
// (1193180 Hz) by, to get our required frequency. Important to note is
// that the divisor must be small enough to fit into 16-bits.
uint32_t divisor = 1193180 / frequency;
// Send the command byte.
Ports::outportb(0x43, 0x34);
// Divisor has to be sent byte-wise, so split here into upper/lower bytes.
uint8_t l = (uint8_t)(divisor & 0xFF);
uint8_t h = (uint8_t)( (divisor>>8) & 0xFF );
// Send the frequency divisor.
Ports::outportb(0x40, l);
Ports::outportb(0x40, h);
}
extern "C" void kernel_main()
{
video.initialize();
video.clearScreen(COLOR_BLACK);
idtStart();
asm volatile ("sti");
init_timer(50);
}