Keyboard: Problem with the (re)programmed Interrupt handler
Keyboard: Problem with the (re)programmed Interrupt handler
Hi all
I recently started on this project of devving a nice personal tool kit that would boot off from a CD, and instead went to OS Development.
I have worked hard for 2 weeks or so, and got the bootsector working. Successful linking of assembler code to start my kernel.
Loading sectors properly.
Reaching the PMode.
Loaded the GDT, IDT ... no LDT so far.
Now, I left assembly and started coding in C.
Now, the problematic part.
I got my keyboard interrupt written. It *works*. The function runs whenever I hit a key. Thats fine.
But, how do I *wait* for a key to be pressed? i.e. to program the getch() function?
I did:
(Pseudo code)
Buffer [0 ... 0xFF] //Software buffer
While the buffer position of the software buffer isnt zero, run an infinite loop:
while(buffer_pos == 0);
buffer_pos is zero initially.
But, now, if i hit a key, it doenst even respond. I have found that it gets stuck at this while loop.
And, the buffer_pos is *volatile* data type. So, no optimizations are done.
So, how do i solve this problem?
My question is: If the CPU is interrupted (IRQ1, Keyboard), does it stop executing *whatever* it is executing? i.e.: even an infinite looP?
Thanks!
PS:
I am using VMWare for testing.
Floppy image / an El-Torito bootable CD is used.
I recently started on this project of devving a nice personal tool kit that would boot off from a CD, and instead went to OS Development.
I have worked hard for 2 weeks or so, and got the bootsector working. Successful linking of assembler code to start my kernel.
Loading sectors properly.
Reaching the PMode.
Loaded the GDT, IDT ... no LDT so far.
Now, I left assembly and started coding in C.
Now, the problematic part.
I got my keyboard interrupt written. It *works*. The function runs whenever I hit a key. Thats fine.
But, how do I *wait* for a key to be pressed? i.e. to program the getch() function?
I did:
(Pseudo code)
Buffer [0 ... 0xFF] //Software buffer
While the buffer position of the software buffer isnt zero, run an infinite loop:
while(buffer_pos == 0);
buffer_pos is zero initially.
But, now, if i hit a key, it doenst even respond. I have found that it gets stuck at this while loop.
And, the buffer_pos is *volatile* data type. So, no optimizations are done.
So, how do i solve this problem?
My question is: If the CPU is interrupted (IRQ1, Keyboard), does it stop executing *whatever* it is executing? i.e.: even an infinite looP?
Thanks!
PS:
I am using VMWare for testing.
Floppy image / an El-Torito bootable CD is used.
Re:Keyboard: Problem with the (re)programmed Interrupt handl
that is very weird because that is exactly how my keyboard irq works. I noticed with some compilers that "char volatile" doesnt make it volatile but "volatile char" does.
if it helps any this is my keyboard irq and getkey
if it helps any this is my keyboard irq and getkey
Code: Select all
volatile shift_locks shifts;
volatile unsigned int keycount=0;
volatile unsigned char keys[128];
unsigned char get_kbd_buffer(unsigned char *scan_buf,unsigned char *asc_buf){
keycount--;
*scan_buf=keys[keycount];
keycount--;
*asc_buf=keys[keycount];
return *asc_buf;
}
char getkey(char *buf){
//char tmp[1]; error! allocated on stack
while(keycount==0){}
get_kbd_buffer(&buf[0],&buf[1]);
return buf[1];
}
void waitkey(){
char tmp[1];
while(keycount==0){}
get_kbd_buffer(&tmp[0],&tmp[1]);
}
/*F6-F10 are reserved for window functions and are not useable in applications*/
extern int TextUI;
extern WINDOW mcon;
void kbd_handler(r){
unsigned char scancode;unsigned char tmp;
if (keycount==128){return 0;}
scancode = inportb(0x60);
if (scancode & 0x80) { //this i thought meant that the key was released
switch (scancode) {
case 42|0x80:
shifts.shift=0;
break;
case 54|0x80:
shifts.shift=0;
break;
case 29|0x80:
shifts.ctrl=0;
break;
case 56|0x80:
shifts.alt=0;
break;
}
}else{
switch (scancode){
case 42:
shifts.shift=1;
break;
case 54:
shifts.shift=1;
break;
case 29:
shifts.ctrl=1;
break;
case 56:
shifts.alt=1;
break;
case 58:
shifts.caps=shifts.caps ^ 1;
break;
case 69:
shifts.num=shifts.num ^ 1;
break;
case 70:
shifts.scroll=shifts.scroll ^ 1;
break;
}
if (TextUI==1){
switch(scancode){
case 0x40:
cwin=def_console;
break;
case 0x41:
cwin=&mcon;
break;
case 0x42:
break;
case 0x43:
break;
case 0x44:
break;
}
}
tmp=scan2asc(scancode);
put_kbd_buffer(scancode,tmp);
}
}
Re:Keyboard: Problem with the (re)programmed Interrupt handl
Thanks.
I will try both
volatile char
and
char volatile
and check.
But, is it better to code the driver in assembly?
If i do it in assembly, do i need to specify like: extern kbd_driver blah blah in the C code? I hope the linker takes care of it.
But, then, I need to know the calling convention of C right? To know the parameters passed. I can return data, etc.
Thanks for your time though!
Vimal
I will try both
volatile char
and
char volatile
and check.
But, is it better to code the driver in assembly?
If i do it in assembly, do i need to specify like: extern kbd_driver blah blah in the C code? I hope the linker takes care of it.
But, then, I need to know the calling convention of C right? To know the parameters passed. I can return data, etc.
Thanks for your time though!
Vimal
Re:Keyboard: Problem with the (re)programmed Interrupt handl
Yes.j.vimal wrote: My question is: If the CPU is interrupted (IRQ1, Keyboard), does it stop executing *whatever* it is executing? i.e.: even an infinite looP?
That would be a compiler bug. I wouldn't expect that to happen with e.g. GCC.I noticed with some compilers that "char volatile" doesnt make it volatile but "volatile char" does.
You might want to check out the FAQ on interrupt handlers and what to take care of if you want them written in C. (They require special return handling.)But, is it better to code the driver in assembly?
For any function you call in C, you should have a declaration, i.e. the function name, parameter list, and return type be written in a header file and included prior to using it. A function declaration is by default "extern", so you don't have to say so explicitly (except if you are coding C++, in which case you need [tt]extern "C"[/tt] to make the compiler use the C naming / calling convention.If i do it in assembly, do i need to specify like: extern kbd_driver blah blah in the C code?
Yes.But, then, I need to know the calling convention of C right?
Every good solution is obvious once you've found it.
Re:Keyboard: Problem with the (re)programmed Interrupt handl
Ok.
Got the point.
This is the code I had... I didn't understand it quite well.
void kbd_interrupt()
{
unsigned char kbd_ascii_code=0;
disable();
outportb(0x20,0x20); //ack
kbd_scancode = inportb(0x60);
.... rest of the handling code ....
...i.e choose the character
outportb(0x20,0x20);
enable();
interrupted = 1;
asm("mov %ebp,%esp");
asm("pop %ebp");
asm("iret");
}
So, this is the main problem? The last iret line?
But, I have not saved the initial stage... But ... ?
I dont get it!
Vimal
Got the point.
This is the code I had... I didn't understand it quite well.
void kbd_interrupt()
{
unsigned char kbd_ascii_code=0;
disable();
outportb(0x20,0x20); //ack
kbd_scancode = inportb(0x60);
.... rest of the handling code ....
...i.e choose the character
outportb(0x20,0x20);
enable();
interrupted = 1;
asm("mov %ebp,%esp");
asm("pop %ebp");
asm("iret");
}
So, this is the main problem? The last iret line?
But, I have not saved the initial stage... But ... ?
I dont get it!
Vimal
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Keyboard: Problem with the (re)programmed Interrupt handl
this is horrible black magic ... you shouldn't use that. consider writing a proper ISR stub that calls your C function instead. That should be easy to find in the FAQ.asm("mov %ebp,%esp");
asm("pop %ebp");
asm("iret");
http://www.osdev.org/osfaq2/
Re:Keyboard: Problem with the (re)programmed Interrupt handl
Exactly what I had thought. Thanks... I will let you all know if it works
Vimal
Vimal
Re:Keyboard: Problem with the (re)programmed Interrupt handl
Hi all
Tried it... didn't work. Using Bochs now.
I had written the assembly wrapper, the calls are working fine... but the main problem now is that it again get stuck with the while loop / even the if conditions i had put.
The "I am here" messages were for debugging. But, they didnt work. The while loop / if statement gets stuck...
Thanks for your time to help me out
Vimal
Tried it... didn't work. Using Bochs now.
I had written the assembly wrapper, the calls are working fine... but the main problem now is that it again get stuck with the while loop / even the if conditions i had put.
Code: Select all
void kbd_interrupt()
{
//our new Keyboard Interrupt
unsigned char kbd_ascii_code=0;
disable(); //Let an interrupt not interrupt another
kbd_scancode = inportb(0x60);
outportb(0x20,0x20); //Acknowledge it
kbd_shift=0,kbd_caps=0;
if(1/*!kbd_special(kbd_scancode)*/)
{
if(kbd_shift)
{
if(!kbd_caps)
kbd_ascii_code = kbd_shifted[kbd_scancode];
else
kbd_ascii_code = kbd_caps_shifted[kbd_scancode];
}
else
{
if(!kbd_caps)
kbd_ascii_code = kbd_normal[kbd_scancode];
else
kbd_ascii_code = kbd_capsnormal[kbd_scancode];
}
if(kbd_buffer_pos != eob)
kbd_buffer[kbd_buffer_pos++]=kbd_ascii_code;
else
{
kbd_buffer[kbd_buffer_pos] =kbd_ascii_code;
kbd_buffer_pos=0;
}
}
outportb(0x20,0x20);
enable();
kbd_flush_buffer(); //flush
interrupted = 1;
}
unsigned char kbd_getch() // Waits for a key to enter the buffer and returns it
{
int i = 0;
//print((unsigned char *)"I am here");
loop:
if(interrupted == 0) goto loop;
//print((unsigned char *)"Done!");
interrupted=0;
disable(); //something in the buffer... Disable all other interrupts
for(i=0; i < kbd_buffer_pos; i++)
{
kbd_buffer[i] = kbd_buffer[i + 1];
}
kbd_buffer_pos--; //immediately Shift the buffer back
enable();
return (unsigned char)kbd_buffer[0];
}
Thanks for your time to help me out
Vimal
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Keyboard: Problem with the (re)programmed Interrupt handl
i see no definition of your "interrupted" variable. Make sure you declared it volatile: that's why that keyword exist
Re:Keyboard: Problem with the (re)programmed Interrupt handl
interrupted is declared as unsigned volatile char
The only thing is that the CPU is NOT getting interrupted when the while loop is going on. Otherwise, its fine.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Keyboard: Problem with the (re)programmed Interrupt handl
disable() and enable() are not welcome in an interrupt handler. Make sure you used an interrupt gate in your IDT if that's not the case.
Have you tried setting a breakpoint in your ISR handler ? Can you confirm interrupts are enable()d in your main code ? Can you confirm the PIC (and more specifically its mask bits) have been correctly set up?
Have you tried setting a breakpoint in your ISR handler ? Can you confirm interrupts are enable()d in your main code ? Can you confirm the PIC (and more specifically its mask bits) have been correctly set up?
Re:Keyboard: Problem with the (re)programmed Interrupt handl
So, I am NOT supposed to disable other interrupts at all?
The sad thing is that, the interrupt actually works if I remove the checking of the (kbd_buffer_pos). Thats what I dont understand. The assembler wrapper works perfectly.
and the Interrupted IS called if I remove the while loop (or if, jump).i didnt debug to check that, but I printed some message and it does print, only when the keyboard button is hit, which means its right. but, the while loop, lol. thats the main problem...
Its getting very very bugging. I might as well code it in assembly. Just waiting for that moment of 'truth'
Vimal
The sad thing is that, the interrupt actually works if I remove the checking of the (kbd_buffer_pos). Thats what I dont understand. The assembler wrapper works perfectly.
and the Interrupted IS called if I remove the while loop (or if, jump).i didnt debug to check that, but I printed some message and it does print, only when the keyboard button is hit, which means its right. but, the while loop, lol. thats the main problem...
Its getting very very bugging. I might as well code it in assembly. Just waiting for that moment of 'truth'
Vimal
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Keyboard: Problem with the (re)programmed Interrupt handl
i think you should give us the declaration and initialization of any global variable you use aswell.
I think i can spot a mistake around here:
Since you are more fluent in assembly than in C, i suggest you give a look at what the compiler produces to validate your assumptions on what it should produce.
e.g. "objdump -drS keyboard.o" might reveal you thing you haven't expected.
I think i can spot a mistake around here:
Code: Select all
- interrupt received, kp_buffer_pos == 0.
- decoded keystroke is stored in kb_buffer[0]
- interupted is set to 1, which "unlocks" the "goto loop" (i suppose the reason you're not using "while (!interrupted)" is just that you had trouble with it.
- getch() will now find kb_buffer_pos==1 and will do the "for" loop with i=0
- that means kb_buffer[0] <-- kb_buffer[1];
- and then you return kb_buffer[1] (which is likely to be zero unless you managed to receive two bytes.
e.g. "objdump -drS keyboard.o" might reveal you thing you haven't expected.
Re:Keyboard: Problem with the (re)programmed Interrupt handl
Yes, that was a wrong code. I will look into that.
Also, I have attached the code for my kernel. kernel0.zip.
Please look into that code, if you have some free time.
Since I dont have internet at my house, I might take a while to reply! Sorry about that!
Vimal
PS: Also, I had checked the disassemlbled object code in a debugger. I find that the volatile is mainted... i.e. I found this:
So, no optimization was done.
Also, I have attached the code for my kernel. kernel0.zip.
Please look into that code, if you have some free time.
Since I dont have internet at my house, I might take a while to reply! Sorry about that!
Vimal
PS: Also, I had checked the disassemlbled object code in a debugger. I find that the volatile is mainted... i.e. I found this:
Code: Select all
loc_sme number:
mov eax,ds:[some address of the kbd_buffer_pos]
cmp eax,0 ;or some equivalent of this.
je loc_sme number
Re:Keyboard: Problem with the (re)programmed Interrupt handl
I have resolved this problem.
The assembly code produced was NOT
But
Is this valid? Doesnt this always return TRUE?
That was the problem. Is this a bug? with gcc?
Vimal
The assembly code produced was NOT
Code: Select all
cmp eax,1
Code: Select all
test eax,eax
That was the problem. Is this a bug? with gcc?
Vimal