Keystroke crashes real PC
-
- Member
- Posts: 81
- Joined: Sun Apr 21, 2019 7:39 am
Keystroke crashes real PC
I have a problem with my keyboard. Every time I press any key, the computer reboots. Doesn't matter if I'm using a real PS/2 keyboard or emulating it, still reboots.
Tested on 3 PCs so far.
I have a suspicion it's somehow linked to keyboard interrupts, but I have no idea how keyboard interrupts work (I'll have to read up on them).
I tried using 'ret' instead of 'iretd', but the code never returns to the program (which is expected, seeing as 'iretd' seems to be an interrupt-specific instruction).
The code works fine in QEMU, haven't tested in VBox or VMware. Will test soon.
Here's the minimal code (still crashes after that).
I've supplied a multiboot ELF file so you can test.
https://github.com/iProgramMC/osdev-example
Tested on 3 PCs so far.
I have a suspicion it's somehow linked to keyboard interrupts, but I have no idea how keyboard interrupts work (I'll have to read up on them).
I tried using 'ret' instead of 'iretd', but the code never returns to the program (which is expected, seeing as 'iretd' seems to be an interrupt-specific instruction).
The code works fine in QEMU, haven't tested in VBox or VMware. Will test soon.
Here's the minimal code (still crashes after that).
I've supplied a multiboot ELF file so you can test.
https://github.com/iProgramMC/osdev-example
-
- Member
- Posts: 5584
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Keystroke crashes real PC
When an interrupt occurs, the CPU loads the CS segment selector from the IDT, and uses that selector to load the segment descriptor from the GDT. When the IRET instruction executes, the CPU pops the CS segment selector from the stack, and uses that selector to load the segment descriptor from the GDT.
Where did you define your GDT?
There are also several places where your code doesn't follow the ABI. It's not a good thing when your interrupt handler clobbers registers.
(On an unrelated note, why do you have so much code in your header files? Headers should be used primarily for declarations, add a few .c files for function definitions.)
Where did you define your GDT?
There are also several places where your code doesn't follow the ABI. It's not a good thing when your interrupt handler clobbers registers.
(On an unrelated note, why do you have so much code in your header files? Headers should be used primarily for declarations, add a few .c files for function definitions.)
-
- Member
- Posts: 81
- Joined: Sun Apr 21, 2019 7:39 am
Re: Keystroke crashes real PC
I thought it wouldn't be required for grub.Octocontrabass wrote: Where did you define your GDT?
What do you mean?Octocontrabass wrote: There are also several places where your code doesn't follow the ABI. It's not a good thing when your interrupt handler clobbers registers.
I don't want to bother with Makefiles.Octocontrabass wrote: (On an unrelated note, why do you have so much code in your header files? Headers should be used primarily for declarations, add a few .c files for function definitions.)
Plus, it gives the advantage that you can essentially store all the code in one file (with a few exceptions, such as assembly code)
-
- Member
- Posts: 5584
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Keystroke crashes real PC
GRUB makes no guarantee about the presence or contents of the GDT. You must define your own GDT before you can do things that rely on the GDT.iProgramInCpp wrote:I thought it wouldn't be required for grub.
The System V ABI guarantees that C functions will preserve EBX, ESI, EDI, EBP, and ESP, but functions can and will change EAX, ECX, and EDX. Since your interrupt handler calls a C function, it can modify EAX/ECX/EDX, potentially corrupting the state of whatever was running at the time the interrupt occurred. You must ensure your interrupt handler saves and restores those registers, or it will cause issues in the future.iProgramInCpp wrote:What do you mean?
Additionally, the ABI requires that the Direction flag is clear when any C function is called. Since your interrupt handler may interrupt a function that was not written in C, you must clear the Direction flag. (However, you don't need to worry about saving or restoring it: the CPU saves the flags when an interrupt occurs, and the IRET instruction restores them.)
You don't need to use a makefile. You can keep using a batch script, or find another build system.iProgramInCpp wrote:I don't want to bother with Makefiles.
I don't see how that's an advantage.iProgramInCpp wrote:Plus, it gives the advantage that you can essentially store all the code in one file (with a few exceptions, such as assembly code)
-
- Member
- Posts: 798
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: Keystroke crashes real PC
This is just to clarify what Octo is saying. The multiboot spec has a warning about this when it says:iProgramInCpp wrote:I thought it wouldn't be required for grub.Octocontrabass wrote: Where did you define your GDT?
The moment the first IRQ fires CS will be reloaded and if there isn't a valid GDTR or GDT you will have problems. You may find that with a real version of GRUB (booting from an ISO for example) and running QEMU with the `-kernel` option to test may behave differently. If it worked it was just by luck.‘GDTR’
Even though the segment registers are set up as described above, the ‘GDTR’ may be invalid, so the OS image must not load any segment registers (even just reloading the same values!) until it sets up its own ‘GDT’.
The Multiboot spec also puts no guarantee on what the selector values for the Code Segment and Data Segment actually are. It does tell you how they will be laid out but doesn't say that selectors have to be a particular value. A Multiboot compliant loader could use CS as 0x08 and another version uses 0x10 (or any other legal values). The same applies to all the data segments as well. The spec says:
You'll note that it says specifically "The exact value is undefined". When you create an IDT you need to specify the value of CS in each IDT entry. If you don't set up your own GDT with the descriptors you need you won't know for certain what CS value to use.‘CS’
Must be a 32-bit read/execute code segment with an offset of ‘0’ and a limit of ‘0xFFFFFFFF’. The exact value is undefined.
‘DS’
‘ES’
‘FS’
‘GS’
‘SS’
Must be a 32-bit read/write data segment with an offset of ‘0’ and a limit of ‘0xFFFFFFFF’. The exact values are all undefined.
Ultimately this basically means with a Multiboot loader you need to use your own GDT the moment you want to use interrupts in protected mode.
-
- Member
- Posts: 81
- Joined: Sun Apr 21, 2019 7:39 am
Re: Keystroke crashes real PC
I'm currently trying to figure out how I can set up the GDT, however my attempt (most recent commit to that code) fails and triple faults on the InitGDT line.
The part I'm stuck in is the "access byte" and "flags" (found it on Wikipedia)
The part I'm stuck in is the "access byte" and "flags" (found it on Wikipedia)
-
- Member
- Posts: 798
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: Keystroke crashes real PC
I wrote a Stackoveflow answer about this Multiboot/GDT issue and I posted some NASM code that sets up a basic GDT. https://stackoverflow.com/a/43171871/3857942
-
- Member
- Posts: 81
- Joined: Sun Apr 21, 2019 7:39 am
Re: Keystroke crashes real PC
I'm currently busy with school, I'll try it when I get home. Thanks!MichaelPetch wrote:I wrote a Stackoveflow answer about this Multiboot/GDT issue and I posted some NASM code that sets up a basic GDT. https://stackoverflow.com/a/43171871/3857942
-
- Member
- Posts: 81
- Joined: Sun Apr 21, 2019 7:39 am
Re: Keystroke crashes real PC
It now works. Thank you very much for your help!