OSDev.org

The Place to Start for Operating System Developers
It is currently Wed Apr 24, 2024 5:06 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 24 posts ]  Go to page Previous  1, 2
Author Message
 Post subject: Re: Cannot get keyboard interrupt handler working
PostPosted: Mon Mar 04, 2019 6:05 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 693
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:
Code:
# 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
In your idt_init function you have:
Code:
idt_ptr[0] = (sizeof (struct IDT_entry) * 286) + ((idt_address & 0xffff) << 16);
. It should be 256, not 286. Near the bottom of the same function you should set the IDT size with something like:
Code:
idt_ptr[0] = (sizeof (IDT)-1) + ((idt_address & 0xffff) << 16);
. 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:
Code:
while(1) asm ("hlt");


Top
 Profile  
 
 Post subject: Re: Cannot get keyboard interrupt handler working
PostPosted: Tue Mar 05, 2019 10:10 am 
Offline

Joined: Tue Jan 08, 2019 7:20 am
Posts: 20
MichaelPetch wrote:
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:
Code:
# 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 0b10011010izeof (IDT)-1) + ((idt_address & 0xffff) << 16);
. You origin
    .byte 0b11001111
    .byte 0x0

gdt_data:
    .short 0xffff
    .short 0x0
    .byte 0x0
    .byte 0b10010010
    .byte 0b11001111
    .byte 0x0izeof (IDT)-1) + ((idt_address & 0xffff) << 16);
. You origin
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
In your idt_init function you have:
Code:
idt_ptr[0] = (sizeof (struct IDT_entry) * 286) + ((idt_address & 0xffff) << 16);
. It should be 256, not 286. Near the bottom of the same function you should set the IDT size with something like:
Code:
idt_ptr[0] = (sizeof (IDT)-1) + ((idt_address & 0xffff) << 16);
. 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:
Code:
while(1) asm ("hlt");

Thanks for the reply! I will surely try it when I can!

EDIT: Now I get an error: can't handle non absolute segment in `ljmp'

_________________
Hello world!


Top
 Profile  
 
 Post subject: Re: Cannot get keyboard interrupt handler working
PostPosted: Tue Mar 05, 2019 11:37 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 693
In your response there is a bunch of junk in the GDT entries that seem to have come from my comments.You will have to move the `.data` section containing the GDT before the `.text` section to avoid the LJMP issue. The file you might wish to try is this one:
Code:
# 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:

.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

# 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

.global load_gdt
# 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


Top
 Profile  
 
 Post subject: Re: Cannot get keyboard interrupt handler working
PostPosted: Tue Mar 05, 2019 11:41 am 
Offline

Joined: Tue Jan 08, 2019 7:20 am
Posts: 20
Nice! It now works! Thank you!

_________________
Hello world!


Top
 Profile  
 
 Post subject: Re: Cannot get keyboard interrupt handler working
PostPosted: Tue Mar 05, 2019 2:08 pm 
Offline

Joined: Tue Jan 08, 2019 7:20 am
Posts: 20
Never mind... For some reason, when I press a key it just prints a line like that one


Attachments:
2019-03-05-215457_726x429_scrot.png
2019-03-05-215457_726x429_scrot.png [ 12.73 KiB | Viewed 1465 times ]

_________________
Hello world!
Top
 Profile  
 
 Post subject: Re: Cannot get keyboard interrupt handler working
PostPosted: Tue Mar 05, 2019 2:51 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 693
You'd have to update your git code. It doesn't behave that way when I run it. That doesn't mean there isn't a problem. If there is one it would likely be your print routine.At this point in time I'd highly recommend starting to use QEMU's remote GDB debugging feature and use GDB to step through the code,set breakpoints etc. This will also mean compiling your code with debug info to be useful.


Top
 Profile  
 
 Post subject: Re: Cannot get keyboard interrupt handler working
PostPosted: Tue Mar 05, 2019 3:03 pm 
Offline

Joined: Tue Jan 08, 2019 7:20 am
Posts: 20
MichaelPetch wrote:
You'd have to update your git code. It doesn't behave that way when I run it. That doesn't mean there isn't a problem. If there is one it would likely be your print routine.At this point in time I'd highly recommend starting to use QEMU's remote GDB debugging feature and use GDB to step through the code,set breakpoints etc. This will also mean compiling your code with debug info to be useful.

Pushed the updated code

Also followed you on twitter, you're such a kind person and you helped me with like everything. Thanks.

_________________
Hello world!


Top
 Profile  
 
 Post subject: Re: Cannot get keyboard interrupt handler working
PostPosted: Tue Mar 05, 2019 3:32 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 693
Your code in the keyboard handler does this:
Code:
        printf(",");
   printf((char) keyboard_to_ascii(keycode));
It doesn't appear you are using printf correctly.If you want to print out the ASCII character you'd do something like:
Code:
printf(",%c", keyboard_to_ascii(keycode));
That would print out a comma and then the ASCII character.


Top
 Profile  
 
 Post subject: Re: Cannot get keyboard interrupt handler working
PostPosted: Wed Mar 06, 2019 9:33 am 
Offline

Joined: Tue Jan 08, 2019 7:20 am
Posts: 20
MichaelPetch wrote:
Your code in the keyboard handler does this:
Code:
        printf(",");
   printf((char) keyboard_to_ascii(keycode));
It doesn't appear you are using printf correctly.If you want to print out the ASCII character you'd do something like:
Code:
printf(",%c", keyboard_to_ascii(keycode));
That would print out a comma and then the ASCII character.

Wow that was such an easy solution! I feel a little bit dumb right now but thanks! Sometimes, small thing do big things

_________________
Hello world!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 24 posts ]  Go to page Previous  1, 2

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 163 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group