Re: Cannot get keyboard interrupt handler working
Posted: Mon Mar 04, 2019 6:05 pm
You likely didn't take seriously the earlier advice in this thread about creating your own GDT. This wasn't just a good idea, it is pretty much a necessity especially if you intend to boot with a real version of GRUB. I have written about this issue on Stackoverflow. The multiboot specification says clearly that you can't rely on the GDT record being valid and that you need to create your own if you intend to reload any of the segment register. This will occur if you use interrupts.
A quick and dirty hack would be to create one in boot.S.Modify that file to be:In your idt_init function you have: . It should be 256, not 286. Near the bottom of the same function you should set the IDT size with something like: . You originally used 286 as well. The IDT structure is the entire size. You have to subtract one from the length before storing it in the IDT record (idt_ptr).
In your kernel_main you should add an infinite loop that issues a hlt. At the very end of that function add:
A quick and dirty hack would be to create one in boot.S.Modify that file to be:
Code: Select all
# Declare constants for the multiboot header.
.set ALIGN, 1<<0 # align loaded modules on page boundaries
.set MEMINFO, 1<<1 # provide memory map
.set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field
.set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot
# Declare a header as in the Multiboot Standard.
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
# Reserve a stack for the initial thread.
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16 KiB
stack_top:
# The kernel entry point.
.section .text
.global _start
.type _start, @function
_start:
movl $stack_top, %esp
# Call the global constructors.
call _init
# Load our own GDT as the multioot GDT record may be invalid
call load_gdt
# Transfer control to the main kernel.
call kernel_main
# Hang if kernel_main unexpectedly returns.
cli
1: # jmp $
hlt
jmp 1b
.size _start, . - _start
# Load GDT and set selectors for a flat memory model
load_gdt:
lgdt (gdtr)
ljmp $CODE_SEL, $.setcs # Set CS selector with far JMP
.setcs:
mov $DATA_SEL, %eax # Set the Data selectors to defaults
mov %eax, %ds
mov %eax, %es
mov %eax, %ss
mov %eax, %fs
mov %eax, %gs
ret
.global load_gdt
.section .data
# GDT with a NULL Descriptor, a 32-Bit code Descriptor
# and a 32-bit Data Descriptor
gdt_start:
gdt_null:
.long 0x0
.long 0x0
gdt_code:
.short 0xffff
.short 0x0
.byte 0x0
.byte 0b10011010
.byte 0b11001111
.byte 0x0
gdt_data:
.short 0xffff
.short 0x0
.byte 0x0
.byte 0b10010010
.byte 0b11001111
.byte 0x0
gdt_end:
# GDT descriptor record
gdtr:
.short gdt_end - gdt_start - 1
.long gdt_start
CODE_SEL = gdt_code - gdt_start
DATA_SEL = gdt_data - gdt_start
Code: Select all
idt_ptr[0] = (sizeof (struct IDT_entry) * 286) + ((idt_address & 0xffff) << 16);
Code: Select all
idt_ptr[0] = (sizeof (IDT)-1) + ((idt_address & 0xffff) << 16);
In your kernel_main you should add an infinite loop that issues a hlt. At the very end of that function add:
Code: Select all
while(1) asm ("hlt");