article

C++ Operating System Development Part 2

Email
Submitted on: 1/5/2015 4:23:00 PM
By: Steve von Takach (from psc cd)  
Level: Advanced
User Rating: By 3 Users
Compatibility: C++ (general)
Views: 1666
 
     To explain how to develop interrupt routines for use in a personal operating system and an introduction on how to write kernel mode drivers.

This article has accompanying files

 
				

Part 2

Part 2 ~ The Keyboard Interrupt

Introduction:

Here we go again. This tutorial is a continuation of part 1 with the aim of developing an interrupt handler for the keyboard. I will also be looking at interrupts in general so that you may use this knowledge to develop other interrupt routines.

Structure of an Interrupt Routine:

An interrupt routine is very similar to a standard routine with a few major differences. The first of these is that an interrupt routine must end with an ‘iret’ instruction instead of a standard ‘ret’ that most c/cpp function routines end in.
This can pose a problem when programming in a high level language such as c/cpp as you may not be able to define the function as an interrupt function to have an ‘iret’ at the end, we will look at away around that later.

(some compilers have built in keywords allowing such definitions as ‘void interrupt IntName(void)’. Many don’t, including GCC which I am using to compile this code)

On top of the need for a slightly different structure to an interrupt routine, when processing an interrupt from a hardware device (compared to a software interrupt) it is required that you inform the device that you have handled the interrupt and then inform the PIC (Programmable Interrupt Controller) that you are ready to receive more interrupts before the processor resumes code execution.

Each piece of hardware must be informed of an interrupt differently, if at all, and requires specific knowledge of how the devices functions to create an interrupt handler for it. The PIC on the other hand is always informed that you are ready to accept more interrupts in the same way each time through the ‘End of Interrupt’ (EOI) command.

The following code shows how to send an EOI when the interrupt comes from the PIC master:

//tell pic we have acknowledged the interrupt

outportb(0x20, 0x20); //Master PIC

The following code shows how to send an EOI when the interrupt comes from the PIC slave:

//tell pic we have acknowledged the interrupt

outportb(0x20, 0x20); //Master PIC

outportb(0xA0, 0x20); //Slave PIC

#Note: the first 8 hardware interrupts (0 – 7) come from the Master PIC and the last 8 (8 – 15) come from the slave PIC.

Now, the problem of making a standard function routine return using an ‘iret’ to make a complete interrupt handling routine. I worked out a method of doing this if your code is compiled in GCC (you will have to do this differently if you use a different compiler or not at all if your compiler has a special keyword for interrupt functions such as Turbo C). The following is an example of a general hardware interrupt routine for the GCC compiler (for other compilers, ignore the bottom 3 lines of code).

void HandlerName(void)

{

disable(); //Disable interrupts, you are already handling one.

//Handler code goes here!!

//Tell PIC that you have handled the interrupt:

outportb(0x20, 0x20); //Master PIC

outportb(0xA0, 0x20); //Slave PIC

enable(); //Enable interrupts so you can receive more

//GCC specific iret code:

asm("mov %ebp,%esp");

asm("pop %ebp");

asm("iret"); //return to executing code

}

That’s it! As you can see, interrupt handlers are not much different from a standard function routine; all they need is a bit of support code. Now how to control the keyboard through interrupts, hence creating a kernel mode keyboard driver. ;0)

A Simple Keyboard Driver:

The keyboard, like most other hardware devices attached to the computer, is a small computer in itself and is actually a very powerful input device allowing you to directly access and command it.

The first thing to know about the keyboard is that when a key is pressed or some information about the current status is waiting, this information is available through the Programmable Peripheral Interface (PPI) port A, or port 0x60. When a keyboard interrupt occurs you must read the data from this port before the keyboard will issue anymore interrupts, it informs the keyboard that you have handled the interrupt and returns any information that may be needed to be handled.

A misunderstanding that many people have with the keyboard is that they think that when a key is pressed it will return the ASCII character code of the key pressed. It does not do this so that the same keyboard can be used in many different languages. How does that work? Well it is quite simple. When a key is pressed, the keyboard returns the index number of that key, meaning any key can be used to represent any character (luckily there are standards for keyboard layouts so we don’t need a specific driver for every keyboard).

Eg. Escape is key 1,

the ~ is key 2,

! is key 3,

@ is key 4 ect. All the way along the keyboard and it is a simple matter of constructing a lookup table for the various ascii values of the keys being pressed.

char normal[] = //Keyboard character maps (Look up table)

{

0x00,0x1B,'1','2','3','4','5','6','7','8','9','0','-','=','\b','\t',

'q','w','e','r','t','y','u','i','o','p','[',']',0x0D,0x80,

'a','s','d','f','g','h','j','k','l',';',047,0140,0x80,

0134,'z','x','c','v','b','n','m',',','.','/',0x80,

'*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,

0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,

0x80,0x80,0x80,'0',0177

};

Of course you will have to construct another one of these tables for if the shift key is being pressed and another when caps lock is on or you could write some code to convert the character codes manually, whatever you want.

An example, simple keyboard handler:

void kbInt(void)

{

unsigned char asciiCode;

unsigned char scanCode; //Last scan code recieved from the keyboard

disable(); //Disable interrupts, you are already handling one.

scanCode = inportb(0x60); //retrieve scan code

asciiCode = normal[scanCode]; //from look up table above

//Tell PIC that you have handled the interrupt:

outportb(0x20, 0x20); //Master PIC

enable(); //Enable interrupts so you can receive more

//GCC specific iret code:

asm("mov %ebp,%esp");

asm("pop %ebp");

asm("iret"); //return to executing code

}

Now that you can determine what key is being pressed, you have to write some interface code so that other programs or parts of your kernel can receive input. The most simple of these interfaces is a ‘getch()’ function that returns the first key pressed in a buffer. I won’t bother showing you that code in this tutorial but an example is included in the attached zip in the ‘kbInt.cpp’ and ‘keyboard.cpp’ files.

The code in the zip also has some more advanced functions such as defining function keys and turning on the keyboard LED’s. I’ve placed comments on all the code and with the information in this tutorial it should be no trouble at all to develop your own keyboard driver.

For more information on keyboard commands and controls see: http://www.nondot.org/sabre/os/files/HCI/KeyboardFAQ.txt

winzip iconDownload article

Note: Due to the size or complexity of this submission, the author has submitted it as a .zip file to shorten your download time. Afterdownloading it, you will need a program like Winzip to decompress it.Virus note:All files are scanned once-a-day by Planet Source Code for viruses, but new viruses come out every day, so no prevention program can catch 100% of them. For your own safety, please:
  1. Re-scan downloaded files using your personal virus checker before using it.
  2. NEVER, EVER run compiled files (.exe's, .ocx's, .dll's etc.)--only run source code.

If you don't have a virus scanner, you can get one at many places on the net including:McAfee.com


Other 1 submission(s) by this author

 


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Advanced category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments


 There are no comments on this submission.
 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)
 

To post feedback, first please login.