Keyboard and Framebuffer issues

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
Senc39
Posts: 5
Joined: Thu Nov 23, 2023 2:07 pm

Keyboard and Framebuffer issues

Post by Senc39 »

https://github.com/Senc3951/MyOS
Hi, I have 2 questions about my OS I hope someone can answer.

1. When testing the keyboard driver, I noticed that if I spam keys, at first everything works and the letters are printed to the screen, however, after a couple of seconds it stops generating interrupts. upon further investigating I saw that if I print the letters only to the serial output and not to the screen (Framebuffer), it will still stop generating interrupts but after a longer time, so I guess it happens because the fb is slow and the kernel doesn't have time to send an EOI while another key is pressed. (located at kernel/src/dev/ps2/kbd, taken from xv6)

2. When initializing the framebuffer and clearing the screen, I saw that it takes around 1.5sec to clear the screen. To speed things up, I mapped it as WC but I can't see a difference. I saw that someone said that it happens because of qemu and on actual hardware it would be faster, but when experimenting with Limine bootloader, the fb reacted way faster although they used the same caching for all the memory (WC for fb, WB for rest). (cache init at kernel/src/mem/vmm, fb at kernel/src/dev/fb/screen)
thewrongchristian
Member
Member
Posts: 406
Joined: Tue Apr 03, 2018 2:44 am

Re: Keyboard and Framebuffer issues

Post by thewrongchristian »

Senc39 wrote:https://github.com/Senc3951/MyOS
Hi, I have 2 questions about my OS I hope someone can answer.

1. When testing the keyboard driver, I noticed that if I spam keys, at first everything works and the letters are printed to the screen, however, after a couple of seconds it stops generating interrupts. upon further investigating I saw that if I print the letters only to the serial output and not to the screen (Framebuffer), it will still stop generating interrupts but after a longer time, so I guess it happens because the fb is slow and the kernel doesn't have time to send an EOI while another key is pressed. (located at kernel/src/dev/ps2/kbd, taken from xv6)
Your interrupt handler will be running with further interrupts disabled, so doing potentially long running (relatively) operations like interpreting the scan code into a character, and echoing it to the screen, will mean your OS will be ignoring further, potentially high priority interrupts until you're done handling all this work.

Your interrupt handler wants to do the minimal amount of work. You want to read the scan code, queue it for further processing (some sort of software FIFO), then get out of interrupt context ASAP.

Once it's in the FIFO, you can schedule a thread to further process the scan code, do any interpretation, echo characters back out etc.

Note also that the PS2 controller also handles mouse input, and if not correctly configured and handled, pending mouse input will block further keyboard input from interrupting.
Senc39 wrote: 2. When initializing the framebuffer and clearing the screen, I saw that it takes around 1.5sec to clear the screen. To speed things up, I mapped it as WC but I can't see a difference. I saw that someone said that it happens because of qemu and on actual hardware it would be faster, but when experimenting with Limine bootloader, the fb reacted way faster although they used the same caching for all the memory (WC for fb, WB for rest). (cache init at kernel/src/mem/vmm, fb at kernel/src/dev/fb/screen)
WC makes no difference to QEMU.

WC works by writing lots of memory together in a single burst over PCI. Normally, when you write, say, a 32-bit word to a PA mapped to a PCI memory address, that 32-bit write will require a whole PCI transaction (bus arbitration, multiple layers of write buffers, synchronisation signals going over long motherboard traces etc.)

WC works by buffering multiple writes to successive PA into the cache, then writing all the changes to the PA range in a single, big burst of writes using PCI burst mode. This means one set of PCI control and arbitration to write a large number of individual writes, amortizing all the overhead across the large number of writes wrapped up in the combined write. This is a big win for framebuffer writes, where the actual order of the writes is not significant.

Obviously, outside of the context of framebuffers, and in the context of PCI device registers, writes to registers must be done in a predictable order. As writes to registers are often triggers to initiate some action, so other registers that act as arguments to the action must have been written previously.
MichaelPetch
Member
Member
Posts: 712
Joined: Fri Aug 26, 2016 1:41 pm
Freenode IRC: mpetch

Re: Keyboard and Framebuffer issues

Post by MichaelPetch »

I noticed that it stops taking keyboard input after 128 characters which also seems to be the input buffer length in console.c:

Code: Select all

#define INPUT_BUF 128
. It also seems to be that after 128 characters it stops processing characters but keyboard interrupts are still being received. I noticed the interrupts being received when I ran with the extra option `-d int` in QFLAGS(config.mk).
Senc39
Posts: 5
Joined: Thu Nov 23, 2023 2:07 pm

Re: Keyboard and Framebuffer issues

Post by Senc39 »

thewrongchristian wrote:
Senc39 wrote:https://github.com/Senc3951/MyOS
Hi, I have 2 questions about my OS I hope someone can answer.

1. When testing the keyboard driver, I noticed that if I spam keys, at first everything works and the letters are printed to the screen, however, after a couple of seconds it stops generating interrupts. upon further investigating I saw that if I print the letters only to the serial output and not to the screen (Framebuffer), it will still stop generating interrupts but after a longer time, so I guess it happens because the fb is slow and the kernel doesn't have time to send an EOI while another key is pressed. (located at kernel/src/dev/ps2/kbd, taken from xv6)
Your interrupt handler will be running with further interrupts disabled, so doing potentially long running (relatively) operations like interpreting the scan code into a character, and echoing it to the screen, will mean your OS will be ignoring further, potentially high priority interrupts until you're done handling all this work.

Your interrupt handler wants to do the minimal amount of work. You want to read the scan code, queue it for further processing (some sort of software FIFO), then get out of interrupt context ASAP.

Once it's in the FIFO, you can schedule a thread to further process the scan code, do any interpretation, echo characters back out etc.

Note also that the PS2 controller also handles mouse input, and if not correctly configured and handled, pending mouse input will block further keyboard input from interrupting.
Senc39 wrote: 2. When initializing the framebuffer and clearing the screen, I saw that it takes around 1.5sec to clear the screen. To speed things up, I mapped it as WC but I can't see a difference. I saw that someone said that it happens because of qemu and on actual hardware it would be faster, but when experimenting with Limine bootloader, the fb reacted way faster although they used the same caching for all the memory (WC for fb, WB for rest). (cache init at kernel/src/mem/vmm, fb at kernel/src/dev/fb/screen)
WC makes no difference to QEMU.

WC works by writing lots of memory together in a single burst over PCI. Normally, when you write, say, a 32-bit word to a PA mapped to a PCI memory address, that 32-bit write will require a whole PCI transaction (bus arbitration, multiple layers of write buffers, synchronisation signals going over long motherboard traces etc.)

WC works by buffering multiple writes to successive PA into the cache, then writing all the changes to the PA range in a single, big burst of writes using PCI burst mode. This means one set of PCI control and arbitration to write a large number of individual writes, amortizing all the overhead across the large number of writes wrapped up in the combined write. This is a big win for framebuffer writes, where the actual order of the writes is not significant.

Obviously, outside of the context of framebuffers, and in the context of PCI device registers, writes to registers must be done in a predictable order. As writes to registers are often triggers to initiate some action, so other registers that act as arguments to the action must have been written previously.
Thanks, I got it now and will try to implement it
Senc39
Posts: 5
Joined: Thu Nov 23, 2023 2:07 pm

Re: Keyboard and Framebuffer issues

Post by Senc39 »

MichaelPetch wrote:I noticed that it stops taking keyboard input after 128 characters which also seems to be the input buffer length in console.c:

Code: Select all

#define INPUT_BUF 128
. It also seems to be that after 128 characters it stops processing characters but keyboard interrupts are still being received. I noticed the interrupts being received when I ran with the extra option `-d int` in QFLAGS(config.mk).
Maybe you are correct but it should still print to the serial output as they are two different things and it doesn't print there also
MichaelPetch
Member
Member
Posts: 712
Joined: Fri Aug 26, 2016 1:41 pm
Freenode IRC: mpetch

Re: Keyboard and Framebuffer issues

Post by MichaelPetch »

In console.c I see:

Code: Select all

         default:
            if (c != 0 && g_input.e - g_input.r < INPUT_BUF)
            {
                c = (c == '\r') ? '\n' : c;
                g_input.buf[g_input.e++ % INPUT_BUF] = c;
                putc_all(c);
`putc_all` puts characters to the screen and the serial port but will only do so if you haven't filled the input buffer which is checked at the beginning of this code snippet. Do you ever take anything out of the keyboard buffer once you put a character in? This sort of goes to the other commenter who mentions where you should do processing. Your interrupt handler should act as a producer by stuffing characters in the buffer and there should be a consumer task that checks if there are characters in the buffer and then retrieves them and processes them (like putting them on the display etc). As you retrieve the characters from the buffer the buffer becomes less full allowing more characters to be added by the interrupt handler. Based on the code your keyboard buffer is essentially a circular queue.
Senc39
Posts: 5
Joined: Thu Nov 23, 2023 2:07 pm

Re: Keyboard and Framebuffer issues

Post by Senc39 »

MichaelPetch wrote:In console.c I see:

Code: Select all

         default:
            if (c != 0 && g_input.e - g_input.r < INPUT_BUF)
            {
                c = (c == '\r') ? '\n' : c;
                g_input.buf[g_input.e++ % INPUT_BUF] = c;
                putc_all(c);
`putc_all` puts characters to the screen and the serial port but will only do so if you haven't filled the input buffer which is checked at the beginning of this code snippet. Do you ever take anything out of the keyboard buffer once you put a character in? This sort of goes to the other commenter who mentions where you should do processing. Your interrupt handler should act as a producer by stuffing characters in the buffer and there should be a consumer task that checks if there are characters in the buffer and then retrieves them and processes them (like putting them on the display etc). As you retrieve the characters from the buffer the buffer becomes less full allowing more characters to be added by the interrupt handler. Based on the code your keyboard buffer is essentially a circular queue.
Oh I see that you are write as the xv6 takes input out of the buffer which I hadn't implemented yet
Post Reply