[SOLVED] ISRs works but IRQs not

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.
Post Reply
maurotram
Posts: 15
Joined: Mon Nov 25, 2019 1:05 pm
Location: Italy

[SOLVED] ISRs works but IRQs not

Post by maurotram »

Hi everyone!

I'm 13 and I'm trying to make my OS just for playing. Please, don't tell me "10 years of programming are needed for this, you're too young, ecc...".
I'm Italian so please forgive me for my bad english.

So, I'll explain my problem. Here are my files about interrupt handling:

interrupt.asm

Code: Select all

; Defined in isr.c
[extern isr_handler]
[extern irq_handler]

; Common ISR code
isr_common_stub:
    ; 1. Save CPU state
	pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
	mov ax, ds ; Lower 16-bits of eax = ds.
	push eax ; save the data segment descriptor
	mov ax, 0x10  ; kernel data segment descriptor
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	push esp ; registers_t *r
    ; 2. Call C handler
    cld ; C code following the sysV ABI requires DF to be clear on function entry
	call isr_handler

    ; 3. Restore state
	pop eax
    pop eax
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	popa
	add esp, 8 ; Cleans up the pushed error code and pushed ISR number
	iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP

; Common IRQ code. Identical to ISR code except for the 'call'
; and the 'pop ebx'
irq_common_stub:
    pusha
    mov ax, ds
    push eax
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    push esp
    cld
    call irq_handler ; Different than the ISR code
    pop ebx  ; Different than the ISR code
    pop ebx
    mov ds, bx
    mov es, bx
    mov fs, bx
    mov gs, bx
    popa
    add esp, 8
    iret

; We don't get information about which interrupt was caller
; when the handler is run, so we will need to have a different handler
; for every interrupt.
; Furthermore, some interrupts push an error code onto the stack but others
; don't, so we will push a dummy error code for those which don't, so that
; we have a consistent stack for all of them.

; First make the ISRs global
global isr0
global isr1
global isr2
global isr3
global isr4
global isr5
global isr6
global isr7
global isr8
global isr9
global isr10
global isr11
global isr12
global isr13
global isr14
global isr15
global isr16
global isr17
global isr18
global isr19
global isr20
global isr21
global isr22
global isr23
global isr24
global isr25
global isr26
global isr27
global isr28
global isr29
global isr30
global isr31
; IRQs
global irq0
global irq1
global irq2
global irq3
global irq4
global irq5
global irq6
global irq7
global irq8
global irq9
global irq10
global irq11
global irq12
global irq13
global irq14
global irq15

; 0: Divide By Zero Exception
isr0:
    push byte 0
    push byte 0
    jmp isr_common_stub

; 1: Debug Exception
isr1:
    push byte 0
    push byte 1
    jmp isr_common_stub

; 2: Non Maskable Interrupt Exception
isr2:
    push byte 0
    push byte 2
    jmp isr_common_stub

; 3: Int 3 Exception
isr3:
    push byte 0
    push byte 3
    jmp isr_common_stub

; 4: INTO Exception
isr4:
    push byte 0
    push byte 4
    jmp isr_common_stub

; 5: Out of Bounds Exception
isr5:
    push byte 0
    push byte 5
    jmp isr_common_stub

; 6: Invalid Opcode Exception
isr6:
    push byte 0
    push byte 6
    jmp isr_common_stub

; 7: Coprocessor Not Available Exception
isr7:
    push byte 0
    push byte 7
    jmp isr_common_stub

; 8: Double Fault Exception (With Error Code!)
isr8:
    push byte 8
    jmp isr_common_stub

; 9: Coprocessor Segment Overrun Exception
isr9:
    push byte 0
    push byte 9
    jmp isr_common_stub

; 10: Bad TSS Exception (With Error Code!)
isr10:
    push byte 10
    jmp isr_common_stub

; 11: Segment Not Present Exception (With Error Code!)
isr11:
    push byte 11
    jmp isr_common_stub

; 12: Stack Fault Exception (With Error Code!)
isr12:
    push byte 12
    jmp isr_common_stub

; 13: General Protection Fault Exception (With Error Code!)
isr13:
    push byte 13
    jmp isr_common_stub

; 14: Page Fault Exception (With Error Code!)
isr14:
    push byte 14
    jmp isr_common_stub

; 15: Reserved Exception
isr15:
    push byte 0
    push byte 15
    jmp isr_common_stub

; 16: Floating Point Exception
isr16:
    push byte 0
    push byte 16
    jmp isr_common_stub

; 17: Alignment Check Exception
isr17:
    push byte 0
    push byte 17
    jmp isr_common_stub

; 18: Machine Check Exception
isr18:
    push byte 0
    push byte 18
    jmp isr_common_stub

; 19: Reserved
isr19:
    push byte 0
    push byte 19
    jmp isr_common_stub

; 20: Reserved
isr20:
    push byte 0
    push byte 20
    jmp isr_common_stub

; 21: Reserved
isr21:
    push byte 0
    push byte 21
    jmp isr_common_stub

; 22: Reserved
isr22:
    push byte 0
    push byte 22
    jmp isr_common_stub

; 23: Reserved
isr23:
    push byte 0
    push byte 23
    jmp isr_common_stub

; 24: Reserved
isr24:
    push byte 0
    push byte 24
    jmp isr_common_stub

; 25: Reserved
isr25:
    push byte 0
    push byte 25
    jmp isr_common_stub

; 26: Reserved
isr26:
    push byte 0
    push byte 26
    jmp isr_common_stub

; 27: Reserved
isr27:
    push byte 0
    push byte 27
    jmp isr_common_stub

; 28: Reserved
isr28:
    push byte 0
    push byte 28
    jmp isr_common_stub

; 29: Reserved
isr29:
    push byte 0
    push byte 29
    jmp isr_common_stub

; 30: Reserved
isr30:
    push byte 0
    push byte 30
    jmp isr_common_stub

; 31: Reserved
isr31:
    push byte 0
    push byte 31
    jmp isr_common_stub

; IRQ handlers
irq0:
	push byte 0
	push byte 32
	jmp irq_common_stub

irq1:
	push byte 1
	push byte 33
	jmp irq_common_stub

irq2:
	push byte 2
	push byte 34
	jmp irq_common_stub

irq3:
	push byte 3
	push byte 35
	jmp irq_common_stub

irq4:
	push byte 4
	push byte 36
	jmp irq_common_stub

irq5:
	push byte 5
	push byte 37
	jmp irq_common_stub

irq6:
	push byte 6
	push byte 38
	jmp irq_common_stub

irq7:
	push byte 7
	push byte 39
	jmp irq_common_stub

irq8:
	push byte 8
	push byte 40
	jmp irq_common_stub

irq9:
	push byte 9
	push byte 41
	jmp irq_common_stub

irq10:
	push byte 10
	push byte 42
	jmp irq_common_stub

irq11:
	push byte 11
	push byte 43
	jmp irq_common_stub

irq12:
	push byte 12
	push byte 44
	jmp irq_common_stub

irq13:
	push byte 13
	push byte 45
	jmp irq_common_stub

irq14:
	push byte 14
	push byte 46
	jmp irq_common_stub

irq15:
	push byte 15
	push byte 47
	jmp irq_common_stub
idt.c

Code: Select all

#define low_16(address) (uint16_t)((address) & 0xFFFF)
#define high_16(address) (uint16_t)(((address) >> 16) & 0xFFFF)

void set_idt_gate(int n, uint32_t handler) {
    idt[n].low_offset = low_16(handler);
    idt[n].sel = KERNEL_CS;
    idt[n].always0 = 0;
    idt[n].flags = 0x8E;
    idt[n].high_offset = high_16(handler);
}

void set_idt() {
    idt_reg.base = (uint32_t) &idt;
    idt_reg.limit = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
    /* Don't make the mistake of loading &idt -- always load &idt_reg */
    asm volatile("lidtl (%0)" : : "r" (&idt_reg));
}
isr.c

Code: Select all

isr_t interrupt_handlers[256];

/* Can't do this with a loop because we need the address
 * of the function names */
void isr_install() {
    set_idt_gate(0, (uint32_t)isr0);
    set_idt_gate(1, (uint32_t)isr1);
    set_idt_gate(2, (uint32_t)isr2);
    set_idt_gate(3, (uint32_t)isr3);
    set_idt_gate(4, (uint32_t)isr4);
    set_idt_gate(5, (uint32_t)isr5);
    set_idt_gate(6, (uint32_t)isr6);
    set_idt_gate(7, (uint32_t)isr7);
    set_idt_gate(8, (uint32_t)isr8);
    set_idt_gate(9, (uint32_t)isr9);
    set_idt_gate(10, (uint32_t)isr10);
    set_idt_gate(11, (uint32_t)isr11);
    set_idt_gate(12, (uint32_t)isr12);
    set_idt_gate(13, (uint32_t)isr13);
    set_idt_gate(14, (uint32_t)isr14);
    set_idt_gate(15, (uint32_t)isr15);
    set_idt_gate(16, (uint32_t)isr16);
    set_idt_gate(17, (uint32_t)isr17);
    set_idt_gate(18, (uint32_t)isr18);
    set_idt_gate(19, (uint32_t)isr19);
    set_idt_gate(20, (uint32_t)isr20);
    set_idt_gate(21, (uint32_t)isr21);
    set_idt_gate(22, (uint32_t)isr22);
    set_idt_gate(23, (uint32_t)isr23);
    set_idt_gate(24, (uint32_t)isr24);
    set_idt_gate(25, (uint32_t)isr25);
    set_idt_gate(26, (uint32_t)isr26);
    set_idt_gate(27, (uint32_t)isr27);
    set_idt_gate(28, (uint32_t)isr28);
    set_idt_gate(29, (uint32_t)isr29);
    set_idt_gate(30, (uint32_t)isr30);
    set_idt_gate(31, (uint32_t)isr31);

    // Remap the PIC
    outb(0x20, 0x11);
    outb(0xA0, 0x11);
    outb(0x21, 0x20);
    outb(0xA1, 0x28);
    outb(0x21, 0x04);
    outb(0xA1, 0x02);
    outb(0x21, 0x01);
    outb(0xA1, 0x01);
    outb(0x21, 0x0);
    outb(0xA1, 0x0);

    // Install the IRQs
    set_idt_gate(32, (uint32_t)irq0);
    set_idt_gate(33, (uint32_t)irq1);
    set_idt_gate(34, (uint32_t)irq2);
    set_idt_gate(35, (uint32_t)irq3);
    set_idt_gate(36, (uint32_t)irq4);
    set_idt_gate(37, (uint32_t)irq5);
    set_idt_gate(38, (uint32_t)irq6);
    set_idt_gate(39, (uint32_t)irq7);
    set_idt_gate(40, (uint32_t)irq8);
    set_idt_gate(41, (uint32_t)irq9);
    set_idt_gate(42, (uint32_t)irq10);
    set_idt_gate(43, (uint32_t)irq11);
    set_idt_gate(44, (uint32_t)irq12);
    set_idt_gate(45, (uint32_t)irq13);
    set_idt_gate(46, (uint32_t)irq14);
    set_idt_gate(47, (uint32_t)irq15);

    set_idt(); // Load with ASM
}

/* To print the message which defines every exception */
char *exception_messages[] = {
    "Division By Zero",
    "Debug",
    "Non Maskable Interrupt",
    "Breakpoint",
    "Into Detected Overflow",
    "Out of Bounds",
    "Invalid Opcode",
    "No Coprocessor",

    "Double Fault",
    "Coprocessor Segment Overrun",
    "Bad TSS",
    "Segment Not Present",
    "Stack Fault",
    "General Protection Fault",
    "Page Fault",
    "Unknown Interrupt",

    "Coprocessor Fault",
    "Alignment Check",
    "Machine Check",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",

    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved"
};

void isr_handler(registers_t *r) {
    printf("received interrupt: ");
    printf(itoa(r->int_no));
    printf("\n");
    printf(exception_messages[r->int_no]);
    printf("\n");
}

void register_interrupt_handler(uint8_t n, isr_t handler) {
    interrupt_handlers[n] = handler;
}

void irq_handler(registers_t *r) {
    /* After every interrupt we need to send an EOI to the PICs
     * or they will not send another interrupt again */
    if (r->int_no >= 40) outb(0xA0, 0x20); /* slave */
    outb(0x20, 0x20); /* master */

    /* Handle the interrupt in a more modular way */
    if (interrupt_handlers[r->int_no] != 0) {
        isr_t handler = interrupt_handlers[r->int_no];
        handler(r);
    }
}

void irq_install() {
    /* Enable interruptions */
    asm volatile("sti");
    /* IRQ1: keyboard */
    init_keyboard();
}
init_keyboard.c

Code: Select all

void init_keyboard() {
  register_interrupt_handler(IRQ1, cli_keyboard_handler);
}
cli_keyboard_handler

Code: Select all

static char kbuffer[256];
static size_t index = 0;

/*static void clear_buffer() {
  for (int i = 0; kbuffer[i] != '\0'; i++) kbuffer [i] = '\0';
}*/

static void enter() {
  putchar('\n');
  if (!strncmp(kbuffer, "VER", index)) sh_run(OP_CODE_VER);
  else if (!strncmp(kbuffer, "CLEAR", index)) sh_run(OP_CODE_CLS);
  else if (!strncmp(kbuffer, "HELP", index)) sh_run(OP_CODE_HLP);
  else if (!strncmp(kbuffer, "GUI", index)) {
    sh_run(OP_CODE_GUI);
    return;
  }
  else {
    printf("Comando sconosciuto: ");
    terminal_write(kbuffer, index);
    putchar('\n');
  }
  index = 0;
  printf("MaurOS > ");
}

void cli_keyboard_handler() {
  int scancode = inb(0x60);
  switch(scancode) {
        case 0x1C:
          enter();
          break;
        case 0x0:
          printf("ERROR");
          break;
        case 0x1:
          printf("ESC");
          break;
        case 0x2:
          printf("1");
          kbuffer[index] = '1';
          index++;
          break;
        case 0x3:
          printf("2");
          kbuffer[index] = '2';
          index++;
          break;
        case 0x4:
          printf("3");
          kbuffer[index] = '3';
          index++;
          break;
        case 0x5:
          printf("4");
          kbuffer[index] = '4';
          index++;
          break;
        case 0x6:
          printf("5");
          kbuffer[index] = '5';
          index++;
          break;
        case 0x7:
          printf("6");
          kbuffer[index] = '6';
          index++;
          break;
        case 0x8:
          printf("7");
          kbuffer[index] = '7';
          index++;
          break;
        case 0x9:
          printf("8");
          kbuffer[index] = '8';
          index++;
          break;
        case 0xA:
          printf("9");
          kbuffer[index] = '9';
          index++;
          break;
        case 0xB:
          printf("0");
          kbuffer[index] = '0';
          index++;
          break;
        case 0x10:
          printf("Q");
          kbuffer[index] = 'Q';
          index++;
          break;
        case 0x11:
          printf("W");
          kbuffer[index] = 'W';
          index++;
          break;
        case 0x12:
          printf("E");
          kbuffer[index] = 'E';
          index++;
          break;
        case 0x13:
          printf("R");
          kbuffer[index] = 'R';
          index++;
          break;
        case 0x14:
          printf("T");
          kbuffer[index] = 'T';
          index++;
          break;
        case 0x15:
          printf("Y");
          kbuffer[index] = 'Y';
          index++;
          break;
        case 0x16:
          printf("U");
          kbuffer[index] = 'U';
          index++;
          break;
        case 0x17:
          printf("I");
          kbuffer[index] = 'I';
          index++;
          break;
        case 0x18:
          printf("O");
          kbuffer[index] = 'O';
          index++;
          break;
        case 0x19:
          printf("P");
          kbuffer[index] = 'P';
          index++;
          break;
        case 0x1E:
          printf("A");
          kbuffer[index] = 'A';
          index++;
          break;
        case 0x1F:
          printf("S");
          kbuffer[index] = 'S';
          index++;
          break;
        case 0x20:
          printf("D");
          kbuffer[index] = 'D';
          index++;
          break;
        case 0x21:
          printf("F");
          kbuffer[index] = 'F';
          index++;
          break;
        case 0x22:
          printf("G");
          kbuffer[index] = 'G';
          index++;
          break;
        case 0x23:
          printf("H");
          kbuffer[index] = 'H';
          index++;
          break;
        case 0x24:
          printf("J");
          kbuffer[index] = 'J';
          index++;
          break;
        case 0x25:
          printf("K");
          kbuffer[index] = 'K';
          index++;
          break;
        case 0x26:
          printf("L");
          kbuffer[index] = 'L';
          index++;
          break;
        case 0x2C:
          printf("Z");
          kbuffer[index] = 'Z';
          index++;
          break;
        case 0x2D:
          printf("X");
          kbuffer[index] = 'X';
          index++;
          break;
        case 0x2E:
          printf("C");
          kbuffer[index] = 'C';
          index++;
          break;
        case 0x2F:
          printf("V");
          kbuffer[index] = 'V';
          index++;
          break;
        case 0x30:
          printf("B");
          kbuffer[index] = 'B';
          index++;
          break;
        case 0x31:
          printf("N");
          kbuffer[index] = 'N';
          index++;
          break;
        case 0x32:
          printf("M");
          kbuffer[index] = 'M';
          index++;
          break;
        case 0x39:
          printf(" ");
          kbuffer[index] = ' ';
          index++;
          break;
        case 0x0E:
          if (index > 0) {
            putchar('\b');
            index--;
            kbuffer[index] = ' ';
          }
          break;
        case 0x2B:
          printf("\\");
          kbuffer[index] = '\\';
          index++;
          break;
        case 0x34:
          printf(".");
          kbuffer[index] = '.';
          index++;
          break;
        case 0x28:
          printf("\'");
          kbuffer[index] = '\'';
          index++;
          break;
        case 0x0C:
          printf("-");
          kbuffer[index] = '-';
          index++;
          break;
        case 0x33:
          printf(",");
          kbuffer[index] = ',';
          index++;
          break;
        case 0x1A:
          printf("[");
          kbuffer[index] = '[';
          index++;
          break;
        case 0x1B:
          printf("]");
          kbuffer[index] = ']';
          index++;
          break;
        case 0x0D:
          printf("=");
          kbuffer[index] = '=';
          index++;
          break;
        case 0x27:
          printf(";");
          kbuffer[index] = ';';
          index++;
          break;
        default:
          break;
    }
}
kernel.c

Code: Select all

#include <stdio.h>

#include <kernel/tty.h>
#include <kernel/isr.h>
#include <kernel/gdt.h>

void kernel_main() {
	const char* mauros_title = " __  __                   ___  ____\n"
														 "|  \\/  | __ _ _   _ _ __ / _ \\/ ___|\n"
														 "| |\\/| |/ _` | | | | '__| | | \\___ \\\n"
														 "| |  | | (_| | |_| | |  | |_| |___) |\n"
														 "|_|  |_|\\__,_|\\__,_|_|   \\___/|____/\n\n";
	terminal_initialize();
	init_gdt();
	isr_install();
	irq_install();
	printf(mauros_title);
	printf("MaurOS > ");

}
I'm loaded by GRUB. If I try to write "asm volatile("int $2")" it works, the exception is handled and the OS doesn't crash. But I can't receive any IRQ! I'm sure that this code works if I load my system without GRUB. I know that I have to set up a new GDT, and I did with this:

Code: Select all

extern void gdt_flush(uint32_t);

// Internal function prototypes.
void init_gdt();
static void gdt_set_gate(int,uint32_t,uint32_t,uint8_t,uint8_t);

gdt_entry_t gdt_entries[6];
gdt_ptr_t   gdt_ptr;



// Initialisation routine - zeroes all the interrupt service routines,
// initialises the GDT and IDT.

void init_gdt()
{
    gdt_ptr.limit = (sizeof(gdt_entry_t) * 6) - 1;
    gdt_ptr.base  = (uint32_t)&gdt_entries;

    gdt_set_gate(0, 0, 0, 0, 0);                // Null segment
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
    gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
    gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment

    gdt_flush((uint32_t)&gdt_ptr);
}

// Set the value of one GDT entry.
static void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
{
    gdt_entries[num].base_low    = (base & 0xFFFF);
    gdt_entries[num].base_middle = (base >> 16) & 0xFF;
    gdt_entries[num].base_high   = (base >> 24) & 0xFF;

    gdt_entries[num].limit_low   = (limit & 0xFFFF);
    gdt_entries[num].granularity = (limit >> 16) & 0x0F;

    gdt_entries[num].granularity |= gran & 0xF0;
    gdt_entries[num].access      = access;
}
gdt.asm

Code: Select all

[GLOBAL gdt_flush]    ; Allows the C code to call gdt_flush().

gdt_flush:
    mov eax, [esp+4]  ; Get the pointer to the GDT, passed as a parameter.
    lgdt [eax]        ; Load the new GDT pointer

    mov ax, 0x10      ; 0x10 is the offset in the GDT to our data segment
    mov ds, ax        ; Load all data segment selectors
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:.flush   ; 0x08 is the offset to our code segment: Far jump!
.flush:
    ret
P.S.: I'm based on Meaty Skeleton tutorial. Thanks in advance for all useful answers,
Mauro from Italy

P.P.S: I've also tried to handle IRQ0 (I read that it's always fired) but it doesn't work too.
Last edited by maurotram on Mon Jan 04, 2021 3:14 pm, edited 1 time in total.
User avatar
austanss
Member
Member
Posts: 377
Joined: Sun Oct 11, 2020 9:46 pm
Location: United States

Re: ISRs works but IRQs not

Post by austanss »

You need to clear the IRQ mask on the respective IRQ.
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".
maurotram
Posts: 15
Joined: Mon Nov 25, 2019 1:05 pm
Location: Italy

Re: ISRs works but IRQs not

Post by maurotram »

rizxt wrote:You need to clear the IRQ mask on the respective IRQ.
Thank you for the answer! Can you give me a link about this? I tried to search with Google or in thwe wiki but I didn't find anything.
User avatar
austanss
Member
Member
Posts: 377
Joined: Sun Oct 11, 2020 9:46 pm
Location: United States

Re: ISRs works but IRQs not

Post by austanss »

source: https://github.com/microNET-OS/microCOR ... src/io.cxx

Code: Select all

void irq_unmask(uint8_t IRQLine)
{
    uint16_t port;
    uint8_t value;
 
    if (IRQLine < 8)
        port = PIC1_DATA;
    else {
        port = PIC2_DATA;
        IRQLine -= 8;
    }
    value = inb(port) & ~(1 << IRQLine);
    outb(port, value);        
}
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".
thewrongchristian
Member
Member
Posts: 426
Joined: Tue Apr 03, 2018 2:44 am

Re: ISRs works but IRQs not

Post by thewrongchristian »

maurotram wrote:
rizxt wrote:You need to clear the IRQ mask on the respective IRQ.
Thank you for the answer! Can you give me a link about this? I tried to search with Google or in thwe wiki but I didn't find anything.
It's described in the PIC page on the wiki:

https://wiki.osdev.org/PIC#Masking

Basically, when the corresponding bit is set, the IRQ is masked until the bit is reset. The PIC will not deliver masked IRQs, but instead will keep masked IRQs queued until unmasked.
maurotram
Posts: 15
Joined: Mon Nov 25, 2019 1:05 pm
Location: Italy

Re: ISRs works but IRQs not

Post by maurotram »

thewrongchristian wrote:
maurotram wrote:
rizxt wrote:You need to clear the IRQ mask on the respective IRQ.
Thank you for the answer! Can you give me a link about this? I tried to search with Google or in thwe wiki but I didn't find anything.
It's described in the PIC page on the wiki:

https://wiki.osdev.org/PIC#Masking

Basically, when the corresponding bit is set, the IRQ is masked until the bit is reset. The PIC will not deliver masked IRQs, but instead will keep masked IRQs queued until unmasked.
Ok, thank you! I added this method, but I couldn't find where to put the instruction. I tried to put it in my kernel, after connecting the callback to IRQ1, in the keyboard handler but nothing has changed. :?:
clementttttttttt
Member
Member
Posts: 70
Joined: Tue Jul 14, 2020 4:01 am
Libera.chat IRC: clementttttttttt

Re: ISRs works but IRQs not

Post by clementttttttttt »

Have you tried to flush the keyboard buffer?
maurotram
Posts: 15
Joined: Mon Nov 25, 2019 1:05 pm
Location: Italy

Re: ISRs works but IRQs not

Post by maurotram »

clementttttttttt wrote:Have you tried to flush the keyboard buffer?
What do you mean? I can't understand the relationship within the IRQs and my kbuffer
codyd51
Member
Member
Posts: 77
Joined: Fri May 20, 2016 2:29 pm
Location: London, UK
GitHub: https://github.com/codyd51
Contact:

Re: ISRs works but IRQs not

Post by codyd51 »

maurotram wrote: What do you mean? I can't understand the relationship within the IRQs and my buffer
The purpose of an interrupt and interrupt handlers, as I think you understand already, is for an external peripheral device to say "hey, CPU, something happened and I have new data for you!". This act of alerting the CPU is called the interrupt, and the interrupt handler ("interrupt service routine", or ISR) is the bit of code you've set up the CPU to jump to when that particular interrupt is received.

What should the CPU do after being alerted that the device has some new data ready? Well, it should read the data. Your post refers to a PS/2 keyboard in particular, so you should check out the wiki page on how to read data from a PS/2 keyboard: https://wiki.osdev.org/PS/2_Keyboard

In short, within the PS/2 keyboard ISR you should read a byte of data that the keyboard has prepared for you, which it places into port 0x60. You can then do something with this fresh data, such as converting it to an ASCII character and eventually displaying it as user input. This corresponds to the "inb(0x60)" line in the code you've posted. Reading this data in the ISR is what the other commenter meant by "flushing the keyboard buffer".

Note: Others will tell you this, and it's true: in general, you shouldn't interface with the PS/2 keyboard directly, and should instead have an intermediary layer for dealing with the PS/2 controller, to which the PS/2 keyboard is connected. Also, the other commenter might have actually meant to read from port 0x60 before setting up your interrupt handler, just in case the PS/2 keyboard sent a byte before your system was ready to receive it. I understand the fun-factor of working on an OS in this stage, so be mildly aware of this but also enjoy all the progress you make :) have fun!
maurotram
Posts: 15
Joined: Mon Nov 25, 2019 1:05 pm
Location: Italy

Re: ISRs works but IRQs not

Post by maurotram »

codyd51 wrote:
maurotram wrote: What do you mean? I can't understand the relationship within the IRQs and my buffer
Note: Others will tell you this, and it's true: in general, you shouldn't interface with the PS/2 keyboard directly, and should instead have an intermediary layer for dealing with the PS/2 controller, to which the PS/2 keyboard is connected. Also, the other commenter might have actually meant to read from port 0x60 before setting up your interrupt handler, just in case the PS/2 keyboard sent a byte before your system was ready to receive it.
Thank you for this explanation! I tried to read with inb(0x60) before calling isr_install(), but it's still not working... I'll read again the wiki page about PS/2 keyboard, waiting for other helps.
maurotram
Posts: 15
Joined: Mon Nov 25, 2019 1:05 pm
Location: Italy

Re: ISRs works but IRQs not

Post by maurotram »

I think that the problem is "I receive only one IRQ". Because, I've a very simple timer implementation, like this:

Code: Select all

#include <kernel/isr.h>
#include <stdio.h>

uint32_t tick = 0;

static void timer_callback(registers_t regs) {
    tick++;
    printf("Tick: ");

    printf(itoa(tick));
    printf("\n");
}

void init_timer(uint32_t freq) {
    /* Install the function we just wrote */
    register_interrupt_handler(IRQ0, timer_callback);

    /* Get the PIT value: hardware clock at 1193180 Hz */
    uint32_t divisor = 1193180 / freq;
    uint8_t low  = (uint8_t)(divisor & 0xFF);
    uint8_t high = (uint8_t)( (divisor >> 8) & 0xFF);
    /* Send the command */
    outb(0x43, 0x36); /* Command port */
    outb(0x40, low);
    outb(0x40, high);
}
This should print "Tick: n" endless, but prints only one!! So, I think there is an error sending EOI. Right?
I attach a screenshot of my QEMU to explain better my concept.
Image

ONE LAST THING: I notice that if I make an exception manually, such as:

Code: Select all

asm volatile("int $0x20")
(which corresponds to IRQ0, the timer) my handler get called.
maurotram
Posts: 15
Joined: Mon Nov 25, 2019 1:05 pm
Location: Italy

Re: ISRs works but IRQs not

Post by maurotram »

I found the bug!! In my boot.S, when the kernel_main returns, before of the hang instruction there was: cli. I removed this and now all works. Thank you anyway for the answers!!
Post Reply