Page 1 of 1

IDT Causing restart

Posted: Sat Mar 25, 2017 4:13 am
by Garuda1
Hey.

So here's the repo: https://github.com/DxBorks/DxBorks.

The IDT is first initialised in kernel/arch/i386/idt.c

Code: Select all

void idt_init(void)
{
  uint32_t keyboard_address;
  uint32_t idt_address;
  uint32_t idt_ptr[2];

  keyboard_address = (uint32_t)keyboard_handler;
  IDT[0x21].offset_lowerbits = keyboard_address & 0xFFFF;
  IDT[0x21].selector = KERNEL_CODE_SEGMENT_OFFSET;
  IDT[0x21].zero = 0;
  IDT[0x21].type_attr = INTERRUPT_GATE;
  IDT[0x21].offset_higherbits = (keyboard_address & 0xFFFF0000) >> 16;

  /* Send signals to initialize the PICs
   *
   * The PICs will be initialized using the bit string 00010001 (0x11) as the first Initialisation Control Word (ICW1)
   *
   * BIT    VALUE     DESCRIPTION
   * 0      1         Tells the PIC we're not going to send IC4 during initialisation
   * 1      0         Tells the PIC to cascade another 8259A
   * 2      0         Ignored by most x86 devices
   * 3      0         Use edge triggered mode instead of level triggered mode
   * 4      1         Tells the PIC it has to be initialized
   * 5      0         Required to be 0 by x86 devices
   * 6      0         Required to be 0 by x86 devices
   * 7      0         Required to be 0 by x86 devices
   */

  /* Initialisation Control Word 1 */
  outb(PORT_PIC1_COMMAND, 0x11); /* Initialise master */
  outb(PORT_PIC2_COMMAND, 0x11); /* Initialise slave */

  /* Initialisation Control Word 2 */
  outb(PORT_PIC1_DATA, 0x20); /* Map the master PIC's IRQ0 to 0x20 */
  outb(PORT_PIC2_DATA, 0x28); /* Map the slave PIC's IRQ8 to 0x28 */
                              /* The master can only handle interrupts 0x20 to 0x27 */

  /* Initialisation Control Word 3 */
  outb(PORT_PIC1_DATA, 0x04); /* 0100 (BIT1=1) Tell the master the slave is connected to IRQ2 */
  outb(PORT_PIC2_DATA, 0x02); /* Tells the slave IR2 is the communication line with the master */

  /* Initialisation Control Word 4 (required by ICW1) */
  /* This ICW will only be used to signal the PICS we're in x86 mode */
  outb(PORT_PIC1_DATA, 0x01); /* 00000001, the first bit signals the x86 mode (0 means MCS-80/86 mode) */
  outb(PORT_PIC2_DATA, 0x01);

  /* Send EOI to master */
  outb(PORT_PIC1_COMMAND, 0x20);

  /* We now need to clear out the PIC data registers... we don't want garbage in there */
  outb(PORT_PIC1_DATA, 0x00);
  outb(PORT_PIC2_DATA, 0x00);

  idt_address = (uint32_t)IDT;
  idt_ptr[0] = (sizeof(t_IDT_entry) * IDT_SIZE) + ((idt_address & 0xFFFF) << 16);
  idt_ptr[1] = idt_address >> 16;

  /* Load the Interrupt Descriptor Table */
  load_idt((uint32_t)idt_ptr);
}
before being loaded by an assembly function in kernel/arch/i386/idt.s

Code: Select all

.global load_idt
.type   load_idt, @function

.section .text

load_idt:
  mov 4(%esp), %edx
  lidt (%edx)
  sti
  ret
The initialisation starts from kernel/arch/i386/main.c

Code: Select all

void kernel_main(void)
{
  tty_init();
  idt_init();
  keyboard_init();
  serial_init(SERIAL_PORT_0);

  tty_puts(WELCOME_BANNER);

  serial_write(SERIAL_PORT_0, "Hello, world!", 13);
  /*kernel_panic(PANIC_NOTHING, __FILE__, __LINE__);*/
}
around the same time as initialising the screen and serial connections.

- Pressing a key makes the device restart (assumed triple fault)
- The keyboard handler defined in kernel/arch/i386/kb.s doesn't get called
- Execution seems to otherwise be normal. Even though the serial connection isn't working properly at the moment, the debugging feedback appears on the screen signaling that the kernel is still working before pressing a key
- Not initiating the keyboard (by not unmasking the interrupt using the intialisation function in kernel/arch/i386/kb.c works as expected, the device doesn't restart.

Build instructions are defined in documentation.odt but for convenience just cd in the source directory and type in

Code: Select all

$ make & make test
or open the project using Code::Blocks. Not that qemu is required to run it using the test make target.

-----------

How can I prevent this from happening? From what I understand the IDT is not properly setup, the CPU tries to jump at an unknown address, executes garbage, and restarts. I've been trying to fix this for a few weeks now, can anyone help me fix this? Thanks a lot!

Re: IDT Causing restart

Posted: Sat Mar 25, 2017 10:54 am
by LtG
How do you know the keyboard handler doesn't get called?

Near the end of your idt_init() you say "We now need to clear out the PIC data registers...", are you trying to enable or disable all IRQ's?
http://wiki.osdev.org/8259_PIC#Masking

Also I think it might be a good idea to convey intent in your comments: saying why you do things.

If all interrupts are enabled you will at some point likely get PIT interrupts and your code looks like you've only set IDT entry for keyboard... I would suggest putting all exceptions and all IRQ's there and directing all of them to something that catches them all and prints and error and panics/halts. That way if you ever accidentally get IRQ's at least you get some info.

Also, Bochs might give some useful info..

Re: IDT Causing restart

Posted: Sat Mar 25, 2017 4:55 pm
by Garuda1
I tried adding __asm__("hlt"); in the keyboard handler but execution wasn't halted.

I replaced my own load_idt function with the one provided in the wiki, so now it doesn't restart anymore but the handler still doesn't get called, which confirms again that the IDT is the problem.

I was trying to disable all IRQs but the keyboard one, as I'm not bothering working with other interrupts at the moment. But yeah, I'll give bochs a try if it can help.