Interrupts

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.
Locked
Johnyburd
Posts: 11
Joined: Tue Jul 30, 2013 5:23 pm

Interrupts

Post by Johnyburd »

So far I haven't had much luck with this at all. I don't know if any of what I have is working because none of it works until it all works, so I don't know where the problem is. Here is the various relavant pieces of code.
idt.h

Code: Select all

#ifndef __IDT_H
#define __IDT_H

#define IDT_TASK_32 0x5
#define IDT_INT_16 0x6
#define IDT_TRAP_16 0x7
#define IDT_INT_32 0xE
#define IDT_TRAP_32 0xF
#define IDT_SEG_STORAGE 0x10
#define IDT_DPL0 0x0
#define IDT_DPL1 0x20
#define IDT_DPL2 0x40
#define IDT_DPL3 0x60
#define IDT_PRESENT 0x80

struct IDTDescr{
    uint16_t offset_1; // offset bits 0..15
    uint16_t selector; // a code segment selector in GDT or LDT
    uint8_t zero;      // unused, set to 0
    uint8_t type_attr; // type and attributes, see below
    uint16_t offset_2; // offset bits 16..31
};

struct IDTDescr IDT[48];
void setIdt(void *ptr, uint16_t size);
#endif

Code: Select all

#include "gdt.h"
gdt_descriptor create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
{
    gdt_descriptor descriptor;
 
    // Create the high 32 bit segment
    descriptor  =  limit       & 0x000F0000;         // set limit bits 19:16
    descriptor |= (flag <<  8) & 0x00F0FF00;         // set type, p, dpl, s, g, d/b, l and avl fields
    descriptor |= (base >> 16) & 0x000000FF;         // set base bits 23:16
    descriptor |=  base        & 0xFF000000;         // set base bits 31:24
 
    // Shift by 32 to allow for low part of segment
    descriptor <<= 32;
 
    // Create the low 32 bit segment
    descriptor |= base  << 16;                       // set base bits 15:0
    descriptor |= limit  & 0x0000FFFF;               // set limit bits 15:0
 
    return descriptor;
}
now I have two keyboard codes (i've tried both). one uses else if statements and the other doesn't have the right scan codes for my computer. I think the problem might be here, becauese I don't know how the keyboard sends an interrupt. anyway, here's one

Code: Select all

#include "io.h"
#include "string.h"
int ccol;
int led_stat=0;
int crow;
char keysq[100];
int scan(){
	char oldkey;
	char key;
	for (;;){
		oldkey=key;
		key=inportb(0x60);
		if(!(oldkey==key)){
			return key;
		}
	}
}


void klights(){
	if (led_stat == 0){
		outportb(0x60, 0xED);
		while(inportb(0x64) & 2);
		outportb(0x60, 4);
		while(inportb(0x64) & 2);
		led_stat++;
	}
	else if (led_stat == 1){
		outportb(0x60, 0xED);
		while(inportb(0x64) & 2);
		outportb(0x60, 0);
		while(inportb(0x64) & 2);
		led_stat=0;
	}
}
char * keyboard(){
	for(int i=0;i<100;i++)
		keysq[i] = 0;
	int kcount = 0;
	int code = 0;
	scan(); //so it doesn't think its enter
	outportb(0x60, 0xF4);
	while (1){
		code = scan();
		if (code == 0x01){
			print("esc");
			kcount+=3;
		}
		else if (code == 0x02){
			print("1");
			keysq[kcount]='1';
			kcount++;
		
		}
		else if (code == 0x03){
			print("2");
			keysq[kcount]='2';
			kcount++;
		}
		else if (code == 0x04){
			print("3");
			keysq[kcount]='3';
			kcount++;
		}
		else if (code == 0x05){
			print("4");
			keysq[kcount]='4';
			kcount++;
		}
		else if (code == 0x06){
			print("5");
			keysq[kcount]='5';
			kcount++;
		}
		else if (code == 0x07){
			print("6");
			keysq[kcount]='6';
			kcount++;
		}
		else if (code == 0x08){
			print("7");
			keysq[kcount]='7';
			kcount++;
		}
		else if (code == 0x09){
			print("8");
			keysq[kcount]='8';
			kcount++;
		}
		else if (code == 0x0A){
			print("9");
			keysq[kcount]='9';
			kcount++;
		}
		else if (code == 0x0B){
			print("0");
			keysq[kcount]='0';
			kcount++;
		}
		else if (code == 0x0C){
			print("-");
			keysq[kcount]='-';
			kcount++;
		}
		else if (code == 0x0D){
			print("=");
			keysq[kcount]='=';
			kcount++;
		}
		else if (code == 0x0E){
			if (kcount > 0){
				ccol-=2;
				cursor-=2;
				print(" ");
				cursor-=2;//                    BKSP
				kcount--;
				keysq[kcount]=0;
			}
		}
		else if (code == 0x0F){
			print("    ");
		}
		else if (code == 0x10){
			print("q");
			keysq[kcount]='q';
			kcount++;
		}
		else if (code == 0x11){
			print("w");
			keysq[kcount]='w';
			kcount++;
	
		}
		else if (code == 0x12){
			print("e");
			keysq[kcount]='e';
			kcount++;
		}
		else if (code == 0x13){
			print("r");
			keysq[kcount]='r';
			kcount++;
		}
		else if (code == 0x14){
			print("t");
			keysq[kcount]='t';
			kcount++;
		}
		else if (code == 0x15){
			print("y");
			keysq[kcount]='y';
			kcount++;
		}
		else if (code == 0x16){
			print("u");
			keysq[kcount]='u';
			kcount++;
		}
		else if (code == 0x17){
			print("i");
			keysq[kcount]='i';
			kcount++;
		}
		else if (code == 0x18){
			print("o");
			keysq[kcount]='o';
			kcount++;
		}
		else if (code == 0x19){
			print("p");
			keysq[kcount]='p';
			kcount++;
		}
		else if (code == 0x1A){
			print("[");
			keysq[kcount]='[';
			kcount++;
		}
		else if (code == 0x1B){
			print("]");
			keysq[kcount]=']';
			kcount++;
		}
		else if (code == 0x1C){
							//				ENTER
			code = 0;
			print("\n");
			break;
		}
		else if (code == 0x1D){
			print("lctrl");
			kcount+=5;
		}
		else if (code == 0x1E){
			print("a");
			keysq[kcount]='a';
			kcount++;
		}
		else if (code == 0x1F){
			print("s");
			keysq[kcount]='s';
			kcount++;
		}
		else if (code == 0x20){
			print("d");
			keysq[kcount]='d';
			kcount++;
		}
		else if (code == 0x21){
			print("f");
			keysq[kcount]='f';
			kcount++;
		}
		else if (code == 0x22){
			print("g");
			keysq[kcount]='g';
			kcount++;
		}
		else if (code == 0x23){
			print("h");
			keysq[kcount]='h';
			kcount++;
		}
		else if (code == 0x24){
			print("j");
			keysq[kcount]='j';
			kcount++;
		}
		else if (code == 0x25){
			print("k");
			keysq[kcount]='[';
			kcount++;
		}
		else if (code == 0x26){
			print("l");
			keysq[kcount]='l';
			kcount++;
		}
		else if (code == 0x27){
			print(";");
			keysq[kcount]=';';
			kcount++;
		}
		else if (code == 0x28){
			print("'");
			keysq[kcount]='\'';
			kcount++;
		}
		else if (code == 0x29){
			print("`");
			keysq[kcount]='`';
			kcount++;
		}
		else if (code == 0x2A){
			print("lshift");
			kcount+=6;
		}
		else if (code == 0x2B){
			print("\\");
			kcount++;
		}
		else if (code == 0x2C){
			print("z");
			keysq[kcount]='z';
			kcount++;
		}
		else if (code == 0x2D){
			print("x");
			keysq[kcount]='x';
			kcount++;
		}
		else if (code == 0x2E){
			print("c");
			keysq[kcount]='c';
			kcount++;
		}
		else if (code == 0x2F){
			print("v");
			keysq[kcount]='v';
			kcount++;
		}
		else if (code == 0x30){
			print("b");
			keysq[kcount]='b';
			kcount++;
		}
		else if (code == 0x31){
			print("n");
			keysq[kcount]='n';
			kcount++;
		}
		else if (code == 0x32){
			print("m");
			keysq[kcount]='m';
			kcount++;
		}
		else if (code == 0x33){
			print(",");
			keysq[kcount]=',';
			kcount++;
		}
		else if (code == 0x34){
			print(".");
			keysq[kcount]='.';
			kcount++;
		}
		else if (code == 0x35){
			print("/");
			keysq[kcount]='/';
			kcount++;
		}
		else if (code == 0x36){
			print("rshift");
			kcount+=6;
		}
		else if (code == 0x38){
			print("lalt");
			kcount+=4;
		}
		else if (code == 0x39){
			print(" ");
			kcount++;
		}
		else if (code == 0x3A){
			klights();
		}	
	}
	return keysq;
}
and

Code: Select all

#include "string.h"
#include "io.h"
#include "kb.h"
/* KBDUS means US Keyboard Layout. This is a scancode table
*  used to layout a standard US keyboard. I have left some
*  comments in to give you an idea of what key is what, even
*  though I set it's array index to 0. You can change that to
*  whatever you want using a macro, if you wish! */
unsigned 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 */
};



/* Handles the keyboard interrupt */
void keyboard_handler()
//struct regs *r
{

    unsigned char scancode;

    /* Read from the keyboard's data buffer */
    scancode = inportb(0x60);

    /* If the top bit of the byte we read from the keyboard is
    *  set, that means that a key has just been released */
    if (scancode & 0x80)
    {
        /* You can use this one to see if the user released the
        *  shift, alt, or control keys... */
    }
    else
    {
        /* Here, a key was just pressed. Please note that if you
        *  hold a key down, you will get repeated key press
        *  interrupts. */

        /* Just to show you how this works, we simply translate
        *  the keyboard scancode into an ASCII value, and then
        *  display it to the screen. You can get creative and
        *  use some flags to see if a shift is pressed and use a
        *  different layout, or you can add another 128 entries
        *  to the above layout to correspond to 'shift' being
        *  held. If shift is held using the larger lookup table,
        *  you would add 128 to the scancode when you look for it */
		char hi[2];
		char oldkey;
		char key;
		for (;;){
			oldkey=key;
			key=inportb(0x60);
			if(!(oldkey==key)){
				hi[0] = kbdus[scancode];
				print(hi);
			}
		}
    }
}
and here is the main function

Code: Select all

#include <stdint.h>
#include <string.h>
#include "pic.h"
#include "io.h"
//#include "keyboard.h"
#include "string.h"
#include "gdt.h"
#include "idt.h"
#include "kb.h"
void init_gdt(void);
void init_idt(void);
void exit(void);
void _interrupt_handler(void); 

void kmain(void)
{
    extern uint32_t magic;
    if ( magic != 0x2BADB002 )
    {
    	print("Something went not according to specs.");
		exit();
    }

	kclear();
    print("initializing GDT...\n");
    init_gdt();
    print("initializing IDT...\n");
    init_idt();
	print("initializing keyboard...\n");
	outportb(0x60, 0xF4);
	//print("initializing PICs...\n");
	//init_pics(0x20, 0x28);
	cprint("Jonathan's OS\n", 2);
	update_cursor();
	while (1)
		keyboard_handler();  //this should call one of the keyboard functions
	/*while(1){
		char * input = keyboard();
		if (strcheck(input, "help") == 1){
			print("supported commands:\nhelp - displays this message.\nclear - clears the screen.\nreboot - might make it restart.\n");
		}
		else if (strcheck(input, "clear") ==1)
		{
			kclear();
		}
		else if (strcheck(input, "reboot") == 1)
		{
			exit();
			print("this needs to be fixed.  BAD.");
		}
		else{
			print("don't know that one\n");
		}
	}*/
	
}
void exit(void){
	while(inportb(0x64) & 0x02);
	outportb(0x64, 0xFE);
}
void init_gdt(void) {
    /*GDT[0] = ((sizeof(gdt_descriptor) * GDT_ENTRIES - 1) & 0xFFFF)
            | ((uint32_t)GDT) << 16;*/
    GDT[1] = create_descriptor(0, 0xFFFFF, GDT_CODE_PL0);
    GDT[2] = create_descriptor(0, 0xFFFFF, GDT_DATA_PL0);
    setGdt(GDT, sizeof(GDT));
}
void init_idt(void) {
    for (unsigned int i = 0; i < sizeof(IDT); i++) {
        *(((char *)IDT)+i) = 0;
    }
    IDT[1].offset_1 = ((uint32_t)(&_interrupt_handler)) & 0xFFFF;
    IDT[1].offset_2 = ((uint32_t)(&_interrupt_handler)) >> 16;
    IDT[1].selector = 0x08;
    IDT[1].type_attr = IDT_DPL0 | IDT_INT_32 | IDT_PRESENT;
    setIdt(IDT, sizeof(IDT));
}
void _interrupt_handler(void) {
    print("interrupt");
}
the big block that's commented out only works with one keyboard function. the pic is commented out because of a line that I think disables interrupts.
here is the pics code

Code: Select all

#include "pic.h"
#include "io.h"




void init_pics(int pic1, int pic2)
{
	/* send ICW1 */
	outportb(PIC1, ICW1);
	outportb(PIC2, ICW1);

	/* send ICW2 */
	outportb(PIC1 + 1, pic1);	/* remap */
	outportb(PIC2 + 1, pic2);	/*  pics */

	/* send ICW3 */
	outportb(PIC1 + 1, 4);	/* IRQ2 -> connection to slave */
	outportb(PIC2 + 1, 2);

	/* send ICW4 */
	outportb(PIC1 + 1, ICW4);
	outportb(PIC2 + 1, ICW4);

	/* disable all IRQs */
	outportb(PIC1 + 1, 0xFF);
}

I hope someone can help,
thanks,
johnyburd
User avatar
zhiayang
Member
Member
Posts: 368
Joined: Tue Dec 27, 2011 7:57 am
Libera.chat IRC: zhiayang

Re: Interrupts

Post by zhiayang »

I think everything would move along faster, if:

1. You state exactly what is the issue with the code you have.
2. You don't post a large code dump, followed by 'help me'
3. You state what you've tried to debug the issue, instead of leaving everything to strangers on the internet.


Not to mention your if-else loop is hideously ugly.



EDIT:
Johnyburd wrote: ... because of a line that I think disables interrupts...
Johnyburd wrote: I think

Code: Select all

   /* disable all IRQs */
   outportb(PIC1 + 1, 0xFF);
Perhaps you need to reconsider your problem.
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Interrupts

Post by iansjack »

I get the impression that you are cut and pasting code from various sources without any real understanding of how it works. That is unlikely to be successful with a complicated subject like this.

Learn how to debug - single stepping through code if necessary - and it will help you understand the code and perhaps spot your error. But I doubt that anyone here is going to do that for you.
Johnyburd
Posts: 11
Joined: Tue Jul 30, 2013 5:23 pm

Re: Interrupts

Post by Johnyburd »

My cousin did write some of this. I'm sorry that I wasn't clear, but I believe it should be printing interrupt, everytime a key is pressed on the keyboard. And The reason I'm asking for help is so that I can understand it.
Also, yes I'm sorry about the else if statements, I'm working on that, but the only thing I've tried is using the other keyboard driver (the one without else if) because it came from a tutoral that was supposed to work with interrupts.

So really the question is why isn't it printing "interrupt" and where is the problem.

The reason I need you guys' help is because I don't understand all of the code. I thought this would be a better place to learn it because I could talk to real people.

The only thing that I copied and pasted was the code for the PICs and that's hardly relavant since its never used.

I'm sorry for the vague question at first
Thanks,
Johnyburd
Johnyburd
Posts: 11
Joined: Tue Jul 30, 2013 5:23 pm

Re: Interrupts

Post by Johnyburd »

Could someone at least direct me to a good tutorial?
(besides osdev wiki)
thanks,
johnyburd
User avatar
zhiayang
Member
Member
Posts: 368
Joined: Tue Dec 27, 2011 7:57 am
Libera.chat IRC: zhiayang

Re: Interrupts

Post by zhiayang »

Johnyburd wrote:Could someone at least direct me to a good tutorial?
(besides osdev wiki)
thanks,
johnyburd

Again, as iansjack said, if you don't solve your problem, here's what's going to happen:

1. You'll look for another tutorial (assuming you find one)
2. You'll do what you did and copy-paste the code.
3. It would likely break, so you'd either (a), ask your 'cousin' or (b), ask here.
4. We'd probably ask you to debug your problem again.
5. jmp 0x1


You've shown no evidence of actually trying to debug your problem. The most basic thing you can do is to put halts/print messages every step of the way, that way you know what code is failing and where.

Already your comment
JohnnyBurd wrote: ... because of a line that I think disables interrupts...
shows your total lack of understanding of what you're (or your code is) actually doing.
A shot in the dark here, but
JohnnyBurd wrote: The only thing that I copied and pasted was the code for the PICs and that's hardly relavant since its never used.
might suggest you're not remapping the PICs properly. Clearly, not exactly "hardly relevant", as you say.


Again, it might seem like we're all assholes trying to shoot you down for every little mistake, but the nature of this forum is that there needs to be a certain level of understanding, both between the community here and between you and your code.

First thing's first, use something like bochs to step through your code and find out what's going on.
Johnyburd
Posts: 11
Joined: Tue Jul 30, 2013 5:23 pm

Re: Interrupts

Post by Johnyburd »

Well first, I just want to tell you I haven't copied and pasted any code that is being used here. Also, I realize that I'm not at that level, I just don't know how to get there. I don't understand how to debug it. I wanted you to help me. If you don't want to, then that's fine, but I want help learning how to do it. I don't want a tutorial where I can copy and paste the code. I'm trying to learn it. that's why I asked for a good tutorial.

I don't think its fair to tell me I'm a terrible coder because I said "because of a line that I think disables interrupts..." It was rather obvious there. Being able to read someone else's comments has absolutely nothing to do with my knowledge of the language.

Also, the reason I asked for a good tutorial is that the nature of every single tutorial or forum or wiki that I've come across requires "a certain level of understanding". Consequently, it is totally impossible for people like me to learn how! I hoped talking to real people would help me understand, but like I said, If you don't want to help me, that's fine. I'd just like to know where I can learn about this.

I use bochs to test the os, I'm not sure how that helps... I just want to have some code that explains how it works at every part so I can actually understand and learn.

Thanks,
Johnyburd
User avatar
Minoto
Member
Member
Posts: 89
Joined: Thu May 12, 2011 7:24 pm

Re: Interrupts

Post by Minoto »

You correctly identified your most important problem in your original post:
Johnyburd wrote:I don't know if any of what I have is working because none of it works until it all works, so I don't know where the problem is.
Johnyburd wrote:I don't understand how to debug it. I wanted you to help me. If you don't want to, then that's fine, but I want help learning how to do it.
Here's how to debug:
  1. Find what's broken.
  2. Fix it.
  3. Repeat as needed.
Step 1 is usually the hardest. Don't make it even harder on yourself by writing a bunch of code that you hope will do what you want, and then trying to figure out why it doesn't work when you're done. Instead, break whatever it is that you want to do down into pieces that you can understand on their own, and figure out which pieces depend on which others. Then work on them in order, testing as you go, so that at as you go from one piece to the next, you can be reasonably certain that you're building on a solid foundation, and that any problems you encounter are in the new code.

For example, for interrupts to work at all, you have to be able to create an IDT containing properly-formatted descriptors and tell the processor where to find it. You can test that much by writing a simple handler to print a single character to the screen, pointing a descriptor in your IDT at that handler, and then calling it as a software interrupt. If that much works, you can check your PIC mappings by setting the descriptor for IRQ0 to call that same handler, then unmasking only IRQ0 and enabling interrupts. If you get a bunch of characters printed instead of a triple fault, then your handler is getting called each time the PIT fires (18.2 times per second by default), so you've correctly mapped IRQ0 to that descriptor. Try setting your handler for IRQ1 instead, then unmasking only IRQ1, enabling interrupts, and hitting a key. If it does work, it will only work once since you're not reading the scan code from the keyboard controller, but it will prove that you can register an interrupt handler for the keyboard. Once you're that far, modify your handler to read the actual byte received from the keyboard controller and print it instead of just a single character. Then you should be able to receive and see the full sequence of bytes sent by each keypress / release. And when you can do that, you can start working on converting scan codes to ASCII or whatever representation you want to use, keeping track of alt / ctrl / shift status, etc.

If you have problems with the individual steps, read the wiki. Search the forums. Search the rest of the Web. You're not the first person to have had these problems, or these questions. So take advantage of that fact, and learn from the answers that have already been given. Part of learning is figuring out how to find information and make use of it on your own. If you've done all that and still have questions, then at least try to ask them the smart way.
Johnyburd wrote:Also, the reason I asked for a good tutorial is that the nature of every single tutorial or forum or wiki that I've come across requires "a certain level of understanding". Consequently, it is totally impossible for people like me to learn how!
So who wrote the tutorial that brought the first tutorial writer up to that level of understanding? It's not impossible for you to learn. You just have to do it in manageable pieces.
Johnyburd wrote:I use bochs to test the os, I'm not sure how that helps...
Have you read the part of the Bochs documentation that describes the integrated debugger that lets you step through your code one instruction at a time, check the contents of the registers and memory, and various other things that might help you understand what your code is actually doing when it's not doing what you think it should be doing?
Those who understand Unix are doomed to copy it, poorly.
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Interrupts

Post by iansjack »

Well first, I just want to tell you I haven't copied and pasted any code that is being used here.
...
I don't think its fair to tell me I'm a terrible coder because I said "because of a line that I think disables interrupts..." It was rather obvious there. Being able to read someone else's comments has absolutely nothing to do with my knowledge of the language.
Those two sentences don't make sense taken together. If you haven't used anyone else's code then what is there to understand in the comments?

As for debugging, I would say that you are trying to run before you can walk. Go back to writing some simple programs, both in C and assembler, and learn how to use a debugger to singl-step through them, inspect variables and registers, etc. Once you can do that with a simple program you will be in a better position to start OS coding.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Interrupts

Post by Combuster »

Johnyburd wrote:Well first, I just want to tell you I haven't copied and pasted any code that is being used here.
Google says you're lying. I think that only emphasizes that the first bug that needs to be fixed now is you, and not the code.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Locked